diff --git a/.clang-format b/.clang-format new file mode 100755 index 0000000000..394a4c26e0 --- /dev/null +++ b/.clang-format @@ -0,0 +1,123 @@ +--- +Language: Cpp +# BasedOnStyle: Google +AccessModifierOffset: -4 +AlignAfterOpenBracket: AlwaysBreak +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Left +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: true +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: true +BinPackArguments: true +BinPackParameters: true +BreakBeforeBraces: Custom +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: true + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeInheritanceComma: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: true +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^' + Priority: 2 + - Regex: '^<.*\.h>' + Priority: 1 + - Regex: '^<.*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 4 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: false +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +RawStringFormats: + - Language: TextProto + Delimiters: + - 'pb' + - 'proto' + EnclosingFunctions: + - 'PARSE_TEXT_PROTO' + BasedOnStyle: google + - Language: Cpp + Delimiters: + - 'cc' + - 'cpp' + BasedOnStyle: llvm + CanonicalDelimiter: 'cc' +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +TabWidth: 4 +UseTab: Never +... + diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000000..3decefe3f2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,51 @@ +*/build +*/install +*/download +.externalToolBuilders + +# Python +*.py[cod] + +# C++ +*.so +*.a +*.lai +*.la +*.dylib +*.dll +*.o +*.os +*.slo +*.lo + +# Compilation database +compile_commands.json + +# SCons +.sconsign.dblite +custom*.py +dist +build +install + +# Eclipse +.settings +.*project + +# JetBrains +.idea +cmake-build-* + +# Visual Studio Code +.vscode + +# Generated plugInfo.json files +**/plugInfo.json + +# backup and temp +*.swp +*.bak +*~ + +# mac cruft +.DS_Store diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100755 index 0000000000..cbd66dabe2 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,58 @@ +Contributing to Arnold USD +======================= + +# Do’s and Don’ts + +* **Search tickets before you file a new one.** Add to tickets if you have new information about the issue. +* **Keep tickets short but sweet.** Make sure you include all the context needed to solve the issue. Don't overdo it. Great tickets allow us to focus on solving problems instead of discussing them. +* **Take care of your ticket.** When you spend time to report a ticket with care we'll enjoy fixing it for you. +* **Use [GitHub-flavored Markdown](https://help.github.com/articles/markdown-basics/).** Especially put code blocks and console outputs in backticks (```` ``` ````). That increases the readability. +* **Do not litter.** Don’t add +1’s _unless_ specifically asked for and don’t discuss offtopic issues. + +## Bug Reports + +In short, since you are most likely a developer, provide a ticket that you +_yourself_ would _like_ to receive. + +We depend on _you_ (the community) to contribute in making the project better +for everyone. So debug and reduce your own issues before creating a ticket and +let us know of all the things you tried and their outcome. This applies double +if you cannot share a reproduction with us because of internal company policies. + +Please include steps to reproduce and _all_ other relevant information, +including any other relevant dependency and version information. + +## Feature Requests + +Please try to be precise about the proposed outcome of the feature and how it +would related to existing features. + +## Pull Requests + +We **love** pull requests! + +All contributions _will_ be licensed under the Apache 2.0 license. + +Code/comments should adhere to the following rules: + +* All changes require test coverage (where it's applicable) to ensure it does + not break during refactor work, as well as ensure consistent behavior across + supported platforms. +* Comments are required for public APIs. See Documentation Conventions below. +* When documenting APIs and/or source code, don't make assumptions or make + implications about race, gender, religion, political orientation, or anything + else that isn't relevant to the project. +* Remember that source code usually gets written once and read often: ensure + the reader doesn't have to make guesses. Make sure that the purpose and inner + logic are either obvious to a reasonably skilled professional, or add a + comment that explains it. +* Pull requests will be squashed and merged. Please add a detailed description; + it will be used in the commit message and paraphrased in release notes. + +## More Details + +For coding and documentation conventions check out these sub-pages: + +[Code Conventions](docs/conventions.md) + +[Documentation Conventions](docs/documenting.md) diff --git a/LICENSE.md b/LICENSE.md new file mode 100755 index 0000000000..db04ec5abb --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,585 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + +============= +Luma Pictures +============= + +---------- +usd-arnold +---------- + + Modified Apache 2.0 License + + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor + and its affiliates, except as required to comply with Section 4(c) of + the License and to reproduce the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2019 Luma Pictures + + +============= +RODEOFX +============= + +---------- +OpenWalter +---------- + + WALTER software, © 2018, RodeoFx inc. + + + Modified Apache License for WALTER software + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this license. + "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work. + "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, + irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or + Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, + irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to + those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such + Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution + incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the + date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that + You meet the following conditions: + a.You must give any other recipients of the Work or Derivative Works a copy of this License; and + b.You must cause any modified files to carry prominent notices stating that You changed the files; and + c.You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding + those notices that do not pertain to any part of the Derivative Works; and + d.If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as + part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever + such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices + within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as + modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and + conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you + may have executed with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary + use in describing the origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or + FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of + permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and + grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any + character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or + malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, + indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole + responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted + against, such Contributor by reason of your accepting any such warranty or additional liability. + + +==================== +The SCons Foundation +==================== + +----- +scons +----- + +Copyright (c) 2001 - 2019 The SCons Foundation + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +============= +Eli Bendersky +============= + +-------- +elftools +-------- + +Eli Bendersky (eliben@gmail.com) +This code is in the public domain + +================== +Leonard Richardson +================== + +-------------- +beautiful_soup +-------------- + +Copyright (c) 2004-2010, Leonard Richardson + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of the the Beautiful Soup Consortium and All + Night Kosher Bakery nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE, DAMMIT. + +================ +Jonathan Hartley +================ + +-------- +colorama +-------- + +Copyright (c) 2010 Jonathan Hartley +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holders, nor those of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +=============== +Marcel Hellkamp +=============== + +------ +bottle +------ + +Copyright (c) 2012, Marcel Hellkamp. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100755 index 0000000000..6e249cbbda --- /dev/null +++ b/README.md @@ -0,0 +1,108 @@ +Arnold USD Toolset +======================= + +Arnold USD is a toolset for [Universal Scene Description](https://github.com/PixarAnimationStudios/USD) . The project contains several tools: + +- Arnold Procedural +- Arnold to USD converter command line executable +- Hydra Render Delegate +- Set of USD schemas to describe an Arnold scene using USD + +# Building and Dependencies + +[Building](docs/building.md) + +# Contributing to the Project + +[Contributing](CONTRIBUTING.md) + +# Setting up environment + +After compiling and installing the project + +- Add `/bin` to PATH for the Arnold to USD writer executable. +- Add `/lib/python` to PYTHONPATH for the python schema bindings. +- Add `/plugin` to PXR_PLUGINPATH_NAME for the Hydra Render Delegate. +- Add `/lib/usd` to the PXR_PLUGINPATH_NAME for the USD Schemas. +- Add `/lib` to LD_LIBRARY_PATH on Linux, PATH on Windows and DYLD_LIBRARY_PATH on Mac. + +# Features and Limitations + +## Procedural + +### Features + +- USD shapes : UsdGeomMesh, UsdGeomCurves, UsdGeomPoints, UsdGeomCube, UsdGeomSphere, UsdGeomCone, UsdGeomCylinder. Support for primvars (user data) +- USD Lights : UsdLuxDistantLight, UsdLuxDomeLight, UsdLuxDiskLight, UsdLuxSphereLight, UsdLuxRectLight, UsdLuxGeometryLight.Support for textured lights (dome and rectangle). +- USD native shaders : UsdPreviewSurface, UsdPrimVar*, UsdUVTexture +- Arnold shaders supported as UsdShade nodes (where info:id gives the shader type) +- Support for any additional arnold parameter in USD nodes (ex: attribute arnold:subdiv_iterations in a UsdGeomMesh) +- Support for any arnold node type (ex: Usd type ArnoldSetParameter gets rendered as arnold set_parameter node) +- Support for multi-threaded parsing of a USD file + +### Limitations + +- Nurbs +- Point Instancer +- Cameras + +## Render Delegate + +### Features +- RPrim Support + - Mesh + - All primvars are supported, st/uv is accessible through the built-in uv attribute on the mesh + - Support for the displayColor primvar + - Subdivision settings + - Volume +- SPrim Support + - Material + - Pixar Preview surfaces are translated to arnold nodes, otherwise the info:id attribute is used to determine the shader type + - Distant Light + - Sphere Light + - Disk Light + - Rect Light + - Cylinder Light + - Dome Light +- BPrim Support + - Render Buffer + - OpenVDB Asset +- Point Instancer + - Including nesting of Point Instancers +- Selection in USD View and other applications using the primId aov +- Displaying the Color, Depth and PrimID AOVs +- Motion Blur + - Deformation + - Transformation +- Render Settings via the Render Delegate + - Sampling parameters + - Threading parameters + - Ignore parameters + - Profiling and logging parameters + - Switching between CPU and GPU mode seamlessly + - Default values are configurable through environment variables for most of these parameters + +### Limitations + +- No motion blur support for the Point Instancer attributes +- Can’t preview arbitrary primvar AOVs +- No basisCurves +- No field3d volume grids + - Not all the parameters are accessible through the render settings + - Texture Cache size +- Texture generation parameters (automip, autotile) +- No normal maps on the UsdPreviewSurface +- Only converging renders are supported (ie. it’s not possible to block the viewport until the render finishes) +- No HdExtComputation and UsdSkel computation via the render delegate +- No of physical camera parameters +- No points +- No coordsys support + +### Acknowledgments + +In alphabetical order: + +- Ben Asher +- Chad Dombrova +- Nathan Rusch +- Paul Molodowitch diff --git a/SConstruct b/SConstruct new file mode 100755 index 0000000000..e854d3b58f --- /dev/null +++ b/SConstruct @@ -0,0 +1,463 @@ +# vim: filetype=python +# Copyright 2019 Autodesk, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import glob +import re +import shutil +import sys, os +import platform +from SCons.Script import PathVariable + +# Disable warning about Python 2.6 being deprecated +SetOption('warn', 'no-python-version') + +# Local helper tools +sys.path = [os.path.abspath(os.path.join('tools'))] + sys.path + +from utils import system, configure +from utils.system import IS_WINDOWS, IS_LINUX, IS_DARWIN +from utils.build_tools import * + +# Allowed compilers +if IS_WINDOWS: + ALLOWED_COMPILERS = ['msvc', 'icc'] + arnold_default_api_lib = os.path.join('$ARNOLD_PATH', 'lib') +else: + ALLOWED_COMPILERS = ['gcc', 'clang'] + arnold_default_api_lib = os.path.join('$ARNOLD_PATH', 'bin') + +# Scons doesn't provide a string variable +def StringVariable(key, help, default): + # We always get string values, so it's always valid and trivial to convert + return (key, help, default, lambda k, v, e: True, lambda s: s) + +# Custom variables definitions +vars = Variables('custom.py') +vars.AddVariables( + EnumVariable('MODE', 'Set compiler configuration', 'opt', allowed_values=('opt', 'debug', 'profile')), + EnumVariable('WARN_LEVEL', 'Set warning level', 'none', allowed_values=('strict', 'warn-only', 'none')), + EnumVariable('COMPILER', 'Set compiler to use', ALLOWED_COMPILERS[0], allowed_values=ALLOWED_COMPILERS), + PathVariable('SHCXX', 'C++ compiler used for generating shared-library objects', None), + PathVariable('ARNOLD_PATH', 'Arnold installation root', os.getenv('ARNOLD_PATH', None), PathVariable.PathIsDir), + PathVariable('ARNOLD_API_INCLUDES', 'Where to find Arnold API includes', os.path.join('$ARNOLD_PATH', 'include'), PathVariable.PathIsDir), + PathVariable('ARNOLD_API_LIB', 'Where to find Arnold API static libraries', arnold_default_api_lib, PathVariable.PathIsDir), + PathVariable('ARNOLD_BINARIES', 'Where to find Arnold API dynamic libraries and executables', os.path.join('$ARNOLD_PATH', 'bin'), PathVariable.PathIsDir), + PathVariable('ARNOLD_PYTHON', 'Where to find Arnold python bindings', os.path.join('$ARNOLD_PATH', 'python'), PathVariable.PathIsDir), + PathVariable('USD_PATH', 'USD installation root', os.getenv('USD_PATH', None)), + PathVariable('USD_INCLUDE', 'Where to find USD includes', os.path.join('$USD_PATH', 'include'), PathVariable.PathIsDir), + PathVariable('USD_LIB', 'Where to find USD libraries', os.path.join('$USD_PATH', 'lib'), PathVariable.PathIsDir), + PathVariable('USD_BIN', 'Where to find USD binaries', os.path.join('$USD_PATH', 'bin'), PathVariable.PathIsDir), + EnumVariable('USD_BUILD_MODE', 'Build mode of USD libraries' , 'monolithic' , allowed_values=('shared_libs', 'monolithic', 'static')), + StringVariable('USD_LIB_PREFIX', 'USD library prefix', '' if IS_WINDOWS else 'lib'), + BoolVariable('USD_1910_UPDATED_COMPOSITOR', 'USD-19.10 has the updated compositor interface', False), + # 'static' will expect a static monolithic library "libusd_m". When doing a monolithic build of USD, this + # library can be found in the build/pxr folder + PathVariable('BOOST_INCLUDE', 'Where to find Boost includes', os.path.join('$USD_PATH', 'include', 'boost-1_61'), PathVariable.PathIsDir), + PathVariable('BOOST_LIB', 'Where to find Boost libraries', '.', PathVariable.PathIsDir), + PathVariable('PYTHON_INCLUDE', 'Where to find Python includes (pyconfig.h)', os.getenv('PYTHON_INCLUDE', None)), + PathVariable('PYTHON_LIB', 'Where to find Python libraries (python27.lib) ', os.getenv('PYTHON_LIB', None)), + PathVariable('TBB_INCLUDE', 'Where to find TBB headers.', os.getenv('TBB_INCLUDE', None)), + PathVariable('TBB_LIB', 'Where to find TBB libraries', os.getenv('TBB_LIB', None)), + BoolVariable('TBB_STATIC', 'Wether we link against a static TBB library', False), + EnumVariable('TEST_ORDER', 'Set the execution order of tests to be run', 'reverse', allowed_values=('normal', 'reverse')), + EnumVariable('SHOW_TEST_OUTPUT', 'Display the test log as it is being run', 'single', allowed_values=('always', 'never', 'single')), + EnumVariable('USE_VALGRIND', 'Enable Valgrinding', 'False', allowed_values=('False', 'True', 'Full')), + BoolVariable('UPDATE_REFERENCE', 'Update the reference log/image for the specified targets', False), + PathVariable('PREFIX', 'Directory to install under', '.', PathVariable.PathIsDirCreate), + PathVariable('PREFIX_PROCEDURAL', 'Directory to install the procedural under.', os.path.join('$PREFIX', 'procedural'), PathVariable.PathIsDirCreate), + PathVariable('PREFIX_RENDER_DELEGATE', 'Directory to install the procedural under.', os.path.join('$PREFIX', 'plugin'), PathVariable.PathIsDirCreate), + PathVariable('PREFIX_HEADERS', 'Directory to install the headers under.', os.path.join('$PREFIX', 'include'), PathVariable.PathIsDirCreate), + PathVariable('PREFIX_LIB', 'Directory to install the libraries under.', os.path.join('$PREFIX', 'lib'), PathVariable.PathIsDirCreate), + PathVariable('PREFIX_BIN', 'Directory to install the binaries under.', os.path.join('$PREFIX', 'bin'), PathVariable.PathIsDirCreate), + PathVariable('PREFIX_DOCS', 'Directory to install the documentation under.', os.path.join('$PREFIX', 'docs'), PathVariable.PathIsDirCreate), + PathVariable('PREFIX_THIRD_PARTY', 'Directory to install the third party modules under.', os.path.join('$PREFIX', 'third_party'), PathVariable.PathIsDirCreate), + BoolVariable('SHOW_PLOTS', 'Display timing plots for the testsuite. gnuplot has to be found in the environment path.', False), + BoolVariable('BUILD_SCHEMAS', 'Wether or not to build the schemas and their wrapper.', True), + BoolVariable('BUILD_RENDER_DELEGATE', 'Wether or not to build the hydra render delegate.', True), + BoolVariable('BUILD_USD_WRITER', 'Wether or not to build the arnold to usd writer tool.', True), + BoolVariable('BUILD_PROCEDURAL', 'Wether or not to build the arnold procedural', True), + BoolVariable('BUILD_TESTSUITE', 'Wether or not to build the testsuite', True), + BoolVariable('BUILD_DOCS', 'Wether or not to build the documentation.', True), + BoolVariable('BUILD_HOUDINI_TOOLS', 'Wether or not to build the Houdini tools.', False), + BoolVariable('DISABLE_CXX11_ABI', 'Disable the use of the CXX11 abi for gcc/clang', False), + BoolVariable('USD_HAS_PYTHON_SUPPORT', 'Wether or not the usd build has python support enabled', False), + BoolVariable('BUILD_FOR_KATANA', 'Wether or not buildinf the plugins for Katana', False), + StringVariable('BOOST_LIB_NAME', 'Boost library name pattern', 'boost_%s'), + StringVariable('USD_MONOLITHIC_LIBRARY', 'Name of the USD monolithic library', 'usd_ms'), + StringVariable('PYTHON_LIB_NAME', 'Name of the python library', 'python27'), + ('TEST_PATTERN', 'Glob pattern of tests to be run', 'test_*'), + ('KICK_PARAMS', 'Additional parameters for kick', '-v 6') +) + +# Create the scons environment +env = Environment(variables = vars, ENV = os.environ, tools = ['default', 'doxygen']) + +def get_optional_env_var(env_name): + return env.subst(env[env_name]) if env_name in env else None + +BUILD_SCHEMAS = env['BUILD_SCHEMAS'] +BUILD_RENDER_DELEGATE = env['BUILD_RENDER_DELEGATE'] +BUILD_USD_WRITER = env['BUILD_USD_WRITER'] +BUILD_PROCEDURAL = env['BUILD_PROCEDURAL'] +BUILD_TESTSUITE = env['BUILD_TESTSUITE'] +BUILD_DOCS = env['BUILD_DOCS'] +BUILD_HOUDINI_TOOLS = env['BUILD_HOUDINI_TOOLS'] + +USD_LIB_PREFIX = env['USD_LIB_PREFIX'] + +env['USD_LIB_AS_SOURCE'] = None +# There are two possible behaviors with USD_LIB_PREFIX, if it starts with 'lib' +# then we have to remove it, since gcc and clang automatically substitutes it on +# non windows platforms. If the prefix does not start with lib, then we have to +# force scons to properly link against libs named in a non-standard way. +if not IS_WINDOWS: + if USD_LIB_PREFIX.startswith('lib'): + USD_LIB_PREFIX = USD_LIB_PREFIX[3:] + else: + # Scons needs this variable, so we can pass uniquely named shared + # objects to link against. This is only required on osx and linux. + env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1 + env['USD_LIB_AS_SOURCE'] = True + +env['USD_LIB_PREFIX'] = USD_LIB_PREFIX + +# Forcing the build of the procedural when the testsuite is enabled. +if BUILD_TESTSUITE: + BUILD_PROCEDURAL = True + +ARNOLD_PATH = env.subst(env['ARNOLD_PATH']) +ARNOLD_API_INCLUDES = env.subst(env['ARNOLD_API_INCLUDES']) +ARNOLD_API_LIB = env.subst(env['ARNOLD_API_LIB']) +ARNOLD_BINARIES = env.subst(env['ARNOLD_BINARIES']) + +PREFIX = env.subst(env['PREFIX']) +PREFIX_PROCEDURAL = env.subst(env['PREFIX_PROCEDURAL']) +PREFIX_RENDER_DELEGATE = env.subst(env['PREFIX_RENDER_DELEGATE']) +PREFIX_HEADERS = env.subst(env['PREFIX_HEADERS']) +PREFIX_LIB = env.subst(env['PREFIX_LIB']) +PREFIX_BIN = env.subst(env['PREFIX_BIN']) +PREFIX_DOCS = env.subst(env['PREFIX_DOCS']) +PREFIX_THIRD_PARTY = env.subst(env['PREFIX_THIRD_PARTY']) + +USD_PATH = env.subst(env['USD_PATH']) +USD_INCLUDE = env.subst(env['USD_INCLUDE']) +USD_LIB = env.subst(env['USD_LIB']) +USD_BIN = env.subst(env['USD_BIN']) + +# Storing values after expansion +env['USD_PATH'] = USD_PATH +env['USD_INCLUDE'] = USD_INCLUDE +env['USD_LIB'] = USD_LIB +env['USD_BIN'] = USD_BIN + +# these could be supplied by linux / osx +BOOST_INCLUDE = get_optional_env_var('BOOST_INCLUDE') +BOOST_LIB = get_optional_env_var('BOOST_LIB') +PYTHON_INCLUDE = get_optional_env_var('PYTHON_INCLUDE') +PYTHON_LIB = get_optional_env_var('PYTHON_LIB') +TBB_INCLUDE = get_optional_env_var('TBB_INCLUDE') +TBB_LIB = get_optional_env_var('TBB_LIB') + +if env['COMPILER'] == 'clang': + env['CC'] = 'clang' + env['CXX'] = 'clang++' + +# force compiler to match SHCXX +if env['SHCXX'] != '$CXX': + env['CXX'] = env['SHCXX'] + +# Get Arnold version +env['ARNOLD_VERSION'] = get_arnold_version(ARNOLD_API_INCLUDES) + +# Get USD Version +env['USD_VERSION'] = get_usd_version(USD_INCLUDE) + +if env['COMPILER'] in ['gcc', 'clang'] and env['SHCXX'] != '$CXX': + env['GCC_VERSION'] = os.path.splitext(os.popen(env['SHCXX'] + ' -dumpversion').read())[0] + + +print("Building Arnold-USD:") +print(" - Build mode: '{}'".format(env['MODE'])) +print(" - Host OS: '{}'".format(system.os)) +print(" - Arnold version: '{}'".format(env['ARNOLD_VERSION'])) +#print(" - Environment:") +#for k, v in os.environ.items(): +# print(" {} = {}".format(k,v)) + + +# Platform definitions +if IS_DARWIN: + env.Append(CPPDEFINES = Split('_DARWIN')) + +elif IS_LINUX: + env.Append(CPPDEFINES = Split('_LINUX')) + +elif IS_WINDOWS: + env.Append(CPPDEFINES = Split('_WINDOWS _WIN32 WIN32')) + env.Append(CPPDEFINES = Split('_WIN64')) + + +# Adding USD paths to environment for the teststuite +dylib = 'PATH' if IS_WINDOWS else ('DYLD_LIBRARY_PATH' if IS_DARWIN else 'LD_LIBRARY_PATH') +env_separator = ';' if IS_WINDOWS else ':' + +env.AppendENVPath(dylib, USD_LIB, envname='ENV', sep=env_separator, delete_existing=1) +env.AppendENVPath(dylib, USD_BIN, envname='ENV', sep=env_separator, delete_existing=1) +env.AppendENVPath('PYTHONPATH', os.path.join(USD_LIB, 'python'), envname='ENV', sep=env_separator, delete_existing=1) +env.AppendENVPath('PXR_PLUGINPATH_NAME', os.path.join(USD_PATH, 'plugin', 'usd'), envname='ENV', sep=env_separator, delete_existing=1) +os.environ['PATH'] = env['ENV']['PATH'] +os.putenv('PATH', os.environ['PATH']) +os.environ['PYTHONPATH'] = env['ENV']['PYTHONPATH'] +os.putenv('PYTHONPATH', os.environ['PYTHONPATH']) +os.environ['PXR_PLUGINPATH_NAME'] = env['ENV']['PXR_PLUGINPATH_NAME'] +os.putenv('PXR_PLUGINPATH_NAME', os.environ['PXR_PLUGINPATH_NAME']) + + +# Compiler settings +if env['COMPILER'] in ['gcc', 'clang']: + env.Append(CCFLAGS = Split('-fno-operator-names -std=c++11')) + if env['DISABLE_CXX11_ABI']: + env.Append(CCFLAGS = Split('-D_GLIBCXX_USE_CXX11_ABI=0')) + # Warning level + if env['WARN_LEVEL'] == 'none': + env.Append(CCFLAGS = Split('-w')) + else: + env.Append(CCFLAGS = Split('-Wall -Wsign-compare')) + if env['WARN_LEVEL'] == 'strict': + env.Append(CCFLAGS = Split('-Werror')) + + # Optimization flags + if env['MODE'] == 'opt' or env['MODE'] == 'profile': + env.Append(CCFLAGS = Split('-O3')) + + # Debug and profile flags + if env['MODE'] == 'debug' or env['MODE'] == 'profile': + env.ParseFlags('-DDEBUG') + env.Append(CCFLAGS = Split('-g')) + env.Append(LINKFLAGS = Split('-g')) + env.Append(CCFLAGS = Split('-O0')) + + # Linux profiling + if system.os == 'linux' and env['MODE'] == 'profile': + env.Append(CCFLAGS = Split('-pg')) + env.Append(LINKFLAGS = Split('-pg')) + +# msvc settings +elif env['COMPILER'] == 'msvc': + env.Append(CCFLAGS=Split('/EHsc')) + env.Append(LINKFLAGS=Split('/Machine:X64')) + env.Append(CCFLAGS=Split('/D "NOMINMAX"')) + # Optimization/profile/debug flags + if env['MODE'] == 'opt': + env.Append(CCFLAGS=Split('/O2 /Oi /Ob2 /MD')) + env.Append(CPPDEFINES=Split('NDEBUG')) + elif env['MODE'] == 'profile': + env.Append(CCFLAGS=Split('/Ob2 /MD /Zi')) + else: # debug mode + env.Append(CCFLAGS=Split('/Od /Zi /MD')) + env.Append(LINKFLAGS=Split('/DEBUG')) + +# Add include and lib paths to Arnold +env.Append(CPPPATH = [ARNOLD_API_INCLUDES, USD_INCLUDE]) +env.Append(LIBPATH = [ARNOLD_API_LIB, ARNOLD_BINARIES, USD_LIB]) + +# Add optional include and library paths. These are the standard additional +# libraries required when using USD. +env.Append(CPPPATH = [p for p in [BOOST_INCLUDE, PYTHON_INCLUDE, TBB_INCLUDE] if p is not None]) +env.Append(LIBPATH = [p for p in [BOOST_LIB, PYTHON_LIB, TBB_LIB] if p is not None]) + +# Configure base directory for temp files +BUILD_BASE_DIR = os.path.join('build', '%s_%s' % (system.os, 'x86_64'), '%s_%s' % (env['COMPILER'], env['MODE']), 'usd-%s_arnold-%s' % (env['USD_VERSION'], env['ARNOLD_VERSION'])) + +env['BUILD_BASE_DIR'] = BUILD_BASE_DIR +# Build target +env['ROOT_DIR'] = os.getcwd() + +# Propagate any "library path" environment variable to scons +# if system.os == 'linux': +# add_to_library_path(env, '.') +# if os.environ.has_key('LD_LIBRARY_PATH'): +# add_to_library_path(env, os.environ['LD_LIBRARY_PATH']) +# os.environ['LD_LIBRARY_PATH'] = env['ENV']['LD_LIBRARY_PATH'] +# elif system.os == 'darwin': +# if os.environ.has_key('DYLD_LIBRARY_PATH'): +# add_to_library_path(env, os.environ['DYLD_LIBRARY_PATH']) +# elif system.os == 'windows': +# add_to_library_path(env, os.environ['PATH']) +# os.environ['PATH'] = env['ENV']['PATH'] + +# SCons scripts to build +procedural_script = os.path.join('procedural', 'SConscript') +procedural_build = os.path.join(BUILD_BASE_DIR, 'procedural') + +cmd_script = os.path.join('cmd', 'SConscript') +cmd_build = os.path.join(BUILD_BASE_DIR, 'cmd') + +schemas_script = os.path.join('schemas', 'SConscript') +schemas_build = os.path.join(BUILD_BASE_DIR, 'schemas') + +translator_script = os.path.join('translator', 'SConscript') +translator_build = os.path.join(BUILD_BASE_DIR, 'translator') + +renderdelegate_script = os.path.join('render_delegate', 'SConscript') +renderdelegate_build = os.path.join(BUILD_BASE_DIR, 'render_delegate') +renderdelegate_plug_info = os.path.join('render_delegate', 'plugInfo.json') + +testsuite_build = os.path.join(BUILD_BASE_DIR, 'testsuite') + +# Define targets +# Target for the USD procedural + +if BUILD_PROCEDURAL or BUILD_USD_WRITER: + TRANSLATOR = env.SConscript(translator_script, + variant_dir = translator_build, + duplicate = 0, exports = 'env') + + SConscriptChdir(0) +else: + TRANSLATOR = None + +# Define targets +# Target for the USD procedural +if BUILD_PROCEDURAL: + PROCEDURAL = env.SConscript(procedural_script, + variant_dir = procedural_build, + duplicate = 0, exports = 'env') + SConscriptChdir(0) + + Depends(PROCEDURAL, TRANSLATOR[0]) +else: + PROCEDURAL = None + + +if BUILD_SCHEMAS: + SCHEMAS = env.SConscript(schemas_script, + variant_dir = schemas_build, + duplicate = 0, exports = 'env') + SConscriptChdir(0) +else: + SCHEMAS = None + +if BUILD_USD_WRITER: + ARNOLD_TO_USD = env.SConscript(cmd_script, variant_dir = cmd_build, duplicate = 0, exports = 'env') + SConscriptChdir(0) + Depends(ARNOLD_TO_USD, TRANSLATOR[0]) +else: + ARNOLD_TO_USD = None + +if BUILD_RENDER_DELEGATE: + ARNOLDUSD_HEADER = env.Command(os.path.join(BUILD_BASE_DIR, 'arnold_usd.h'), 'arnold_usd.h.in', configure.configure_header_file) + RENDERDELEGATE = env.SConscript(renderdelegate_script, variant_dir = renderdelegate_build, duplicate = 0, exports = 'env') + SConscriptChdir(0) + Depends(RENDERDELEGATE, ARNOLDUSD_HEADER) +else: + ARNOLDUSD_HEADER = None + RENDERDELEGATE = None + +#Depends(PROCEDURAL, SCHEMAS) + +if BUILD_DOCS: + docs_output = os.path.join(BUILD_BASE_DIR, 'docs') + env['DOXYGEN_TAGS'] = { + 'OUTPUT_DIRECTORY': docs_output + } + DOCS = env.Doxygen(source='docs/Doxyfile', target=docs_output) +else: + DOCS = None + +# Generating plugInfo.json files so we have the right platform specific +# extension. + +plugInfos = [ + renderdelegate_plug_info +] + +for plugInfo in plugInfos: + env.Command(target=plugInfo, source=['%s.in' % plugInfo], + action=configure.configure_plug_info) + +if RENDERDELEGATE: + Depends(RENDERDELEGATE, renderdelegate_plug_info) + +if BUILD_TESTSUITE: + env['USD_PROCEDURAL_PATH'] = os.path.abspath(str(PROCEDURAL[0])) + # copy the usd resources to the same path as the procedural + usd_resource_folder = os.path.join(os.path.dirname(os.path.abspath(str(PROCEDURAL[0]))), 'usd') + if os.path.exists(usd_resource_folder) and not os.path.exists(usd_resource_folder): + shutil.copytree(os.path.join(USD_LIB, 'usd'), usd_resource_folder) + + + + # Target for the test suite + TESTSUITE = env.SConscript(os.path.join('testsuite', 'SConscript'), + variant_dir = testsuite_build, + exports = ['env'], + duplicate = 0) + SConscriptChdir(1) + Depends(TESTSUITE, PROCEDURAL) +else: + TESTSUITE = None + +for target in [RENDERDELEGATE, PROCEDURAL, SCHEMAS, ARNOLD_TO_USD, RENDERDELEGATE, DOCS, TESTSUITE]: + if target: + env.AlwaysBuild(target) + +if TESTSUITE: + env.Alias('testsuite', TESTSUITE) +env.Alias('install', PREFIX) + +# Install compiled dynamic library +if PROCEDURAL: + INSTALL_PROC = env.Install(PREFIX_PROCEDURAL, PROCEDURAL) + env.Alias('procedural-install', INSTALL_PROC) + +if ARNOLD_TO_USD: + INSTALL_ARNOLD_TO_USD = env.Install(PREFIX_BIN, ARNOLD_TO_USD) + env.Alias('writer-install', INSTALL_ARNOLD_TO_USD) + +if RENDERDELEGATE: + INSTALL_RENDERDELEGATE = env.Install(PREFIX_RENDER_DELEGATE, RENDERDELEGATE) + INSTALL_RENDERDELEGATE += env.Install(os.path.join(PREFIX_RENDER_DELEGATE, 'hdArnold', 'resources'), [os.path.join('render_delegate', 'plugInfo.json')]) + INSTALL_RENDERDELEGATE += env.Install(PREFIX_RENDER_DELEGATE, ['plugInfo.json']) + INSTALL_RENDERDELEGATE += env.Install(os.path.join(PREFIX_HEADERS, 'render_delegate'), env.Glob(os.path.join('render_delegate', '*.h'))) + INSTALL_RENDERDELEGATE += env.Install(PREFIX_HEADERS, ARNOLDUSD_HEADER) + env.Alias('delegate-install', INSTALL_RENDERDELEGATE) + +''' +# below are the other dlls we need +env.Install(USD_INSTALL, [os.path.join(env['USD_PATH'], 'bin', 'tbb.dll')]) +env.Install(USD_INSTALL, [os.path.join(env['USD_PATH'], 'bin', 'glew32.dll')]) +env.Install(USD_INSTALL, [os.path.join(env['USD_PATH'], 'lib', 'boost_python-vc140-mt-1_61.dll')]) +''' + +# This follows the standard layout of USD plugins / libraries. +if SCHEMAS: + INSTALL_SCHEMAS = env.Install(PREFIX_LIB, [SCHEMAS[0]]) + INSTALL_SCHEMAS += env.Install(os.path.join(PREFIX_LIB, 'python', 'UsdArnold'), [SCHEMAS[1], os.path.join('schemas', '__init__.py')]) + INSTALL_SCHEMAS += env.Install(os.path.join(PREFIX_LIB, 'usd'), ['plugInfo.json']) + INSTALL_SCHEMAS += env.Install(os.path.join(PREFIX_LIB, 'usd', 'usdArnold', 'resources', 'usdArnold'), [SCHEMAS[2]]) + INSTALL_SCHEMAS += env.Install(os.path.join(PREFIX_LIB, 'usd', 'usdArnold', 'resources'), [SCHEMAS[3], SCHEMAS[4]]) + INSTALL_SCHEMAS += env.Install(os.path.join(PREFIX_HEADERS, 'schemas'), SCHEMAS[5]) + env.Alias('schemas-install', INSTALL_SCHEMAS) + +if DOCS: + INSTALL_DOCS = env.Install(PREFIX_DOCS, DOCS) + env.Alias('docs-install', INSTALL_DOCS) + +if BUILD_HOUDINI_TOOLS: + # There could be a CMakeLists.txt in the root of this folder in the future. + INSTALL_HOUDINI = env.Install(os.path.join(PREFIX_THIRD_PARTY, 'houdini'), os.path.join('third_party', 'houdini', 'scripts')) + INSTALL_HOUDINI = env.Install(os.path.join(PREFIX_THIRD_PARTY, 'houdini'), os.path.join('third_party', 'houdini', 'soho')) + +Default(PREFIX) diff --git a/abuild b/abuild new file mode 100755 index 0000000000..05caa48545 --- /dev/null +++ b/abuild @@ -0,0 +1,4 @@ +#!/bin/sh + +## invokes a local install of scons (forwarding all arguments) +python -B tools/scons/scons.py --site-dir=tools/scons-custom "$@" diff --git a/abuild.bat b/abuild.bat new file mode 100755 index 0000000000..23c2e0b6aa --- /dev/null +++ b/abuild.bat @@ -0,0 +1,3 @@ +@REM invokes a local install of scons (forwarding all arguments) + +@python -B tools\scons\scons.py --site-dir=tools\scons-custom %* diff --git a/arnold_usd.h.in b/arnold_usd.h.in new file mode 100755 index 0000000000..b1030fdb3e --- /dev/null +++ b/arnold_usd.h.in @@ -0,0 +1,26 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#define USED_USD_MAJOR_VERSION ${USD_MAJOR_VERSION} +#define USED_USD_MINOR_VERSION ${USD_MINOR_VERSION} +#define USED_USD_PATCH_VERSION ${USD_PATCH_VERSION} + +#define USED_USD_VERSION_GREATER_EQ(x, y) (USED_USD_MINOR_VERSION >= x && USED_USD_PATCH_VERSION >= y ) || USED_USD_MINOR_VERSION > x || USED_USD_MAJOR_VERSION > 0 + +#define USED_ARNOLD_ARCH_VERSION ${ARNOLD_VERSION_ARCH_NUM} +#define USED_ARNOLD_MAJOR_VERSION ${ARNOLD_VERSION_MAJOR_NUM} +#define USED_ARNOLD_MINOR_VERSION ${ARNOLD_VERSION_MINOR_NUM} + +#define USED_ARNOLD_VERSION_GREATER_EQ(x, y) (USED_ARNOLD_ARCH_VERSION >= x && USED_ARNOLD_MAJOR_VERSION >= y ) || USED_ARNOLD_ARCH_VERSION > x diff --git a/clang_format b/clang_format new file mode 100755 index 0000000000..90bfd53c4c --- /dev/null +++ b/clang_format @@ -0,0 +1,15 @@ +#!/bin/bash + +if [ "$#" == "1" ]; then + SUBFOLDER="$1" +else + SUBFOLDER="." +fi + +if [[ -z "${ARNOLD_USD_CLANG_FORMAT}" ]]; then + CLANG_FORMAT="clang-format" +else + CLANG_FORMAT="${ARNOLD_USD_CLANG_FORMAT}" +fi + +find $SUBFOLDER \( -path './cmake-build-*' -o -path './schemas/build' -o -path ./build \) -prune -o -regex '.*\.\(c\|cpp\|cxx\|h\|hpp\|hxx\)' -exec echo Formatting: {} \; -exec $CLANG_FORMAT -style=file -i {} \; diff --git a/cmd/SConscript b/cmd/SConscript new file mode 100755 index 0000000000..c984208ae3 --- /dev/null +++ b/cmd/SConscript @@ -0,0 +1,103 @@ +# vim: filetype=python +# Copyright 2019 Autodesk, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from utils import system +from utils.build_tools import find_files_recursive +import os +import os.path + +Import('env') +local_env = env.Clone() + +# import build env +src_base_dir = os.path.join(local_env['ROOT_DIR'], 'cmd') +source_files = find_files_recursive(src_base_dir, ['.c', '.cpp']) +include_files = find_files_recursive(src_base_dir, ['.h']) +src_translator_dir = os.path.join(local_env['ROOT_DIR'], 'translator', 'writer') + +# Include paths +includePaths = [ + '.', + env['USD_INCLUDE'], + env['BOOST_INCLUDE'], + env['PYTHON_INCLUDE'], + src_translator_dir +] +local_env.Append(CPPPATH = includePaths) + +local_env.Append(LIBS = ['ai']) + +# Library paths and libraries +libPaths = [ + env['PYTHON_LIB'] +] + +usd_deps = [] +if env['USD_BUILD_MODE'] == 'monolithic': + usd_deps = [ + env['USD_MONOLITHIC_LIBRARY'], + 'tbb', + ] +elif env['USD_BUILD_MODE'] == 'static': + # static builds rely on a monolithic static library + if system.IS_WINDOWS: + usd_deps = [ + '-WHOLEARCHIVE:libusd_m', + 'tbb', + 'Ws2_32', + 'Dbghelp', + 'Shlwapi', + 'advapi32' + ] + else: + usd_deps = [ + 'libusd_m', + 'tbb', + ] +else: # shared libs + usd_deps = [ + 'sdf', + 'tf', + 'usd', + 'ar', + 'usdGeom', + 'usdShade', + 'vt', + 'usdLux', + ] + +translatorLibPath = os.path.abspath(os.path.join(env['BUILD_BASE_DIR'], 'translator')) +libPaths.append(translatorLibPath) +local_env.Append(LIBS = ['usd_translator']) + + +local_env.Append(LIBS = usd_deps) + +local_env.Append(LIBPATH = libPaths) +if local_env['USD_HAS_PYTHON_SUPPORT']: + local_env.Append(LIBS = [env['PYTHON_LIB_NAME'], env['BOOST_LIB_NAME'] % 'python']) + +print '/////////////////////////////////////////////////////////' + +ARNOLD_TO_USD = local_env.Program('arnold_to_usd', source_files) +''' +if system.os() == 'darwin': + local_env.Append(CPPDEFINES = Split('DARWIN')) + local_env.Append(FRAMEWORKS=Split('OpenGl AGL')) + local_env.Append(CPPPATH = '/System/Library/Frameworks/OpenGL.framework/Headers') +''' +Return('ARNOLD_TO_USD') + + + diff --git a/cmd/main.cpp b/cmd/main.cpp new file mode 100755 index 0000000000..66c61c7e6c --- /dev/null +++ b/cmd/main.cpp @@ -0,0 +1,59 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include +#include + +#include "writer.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pxr/usd/sdf/layer.h" +#include "pxr/usd/sdf/path.h" +#include "pxr/usd/usd/stage.h" +#include "pxr/usd/usdGeom/xform.h" + +/** + * Small utility command that converts an Arnold input .ass file into a .usd + *file. It uses the "writer" translator to do it. + **/ +int main(int argc, char** argv) +{ + if (argc < 3) + return -1; + + std::string assname = argv[1]; // 1st command-line argument is the input .ass file + std::string usdname = argv[2]; // 2nd command-line argument is the output .usd file + + // Start the Arnold session, and load the input .ass file + AiBegin(AI_SESSION_INTERACTIVE); + AiASSLoad(assname.c_str()); + + // Create a new USD stage to write out the .usd file + UsdStageRefPtr stage = UsdStage::Open(SdfLayer::CreateNew(usdname)); + + // Create a "writer" Translator that will handle the conversion + UsdArnoldWriter* writer = new UsdArnoldWriter(); + writer->setUsdStage(stage); // give it the output stage + writer->write(nullptr); // do the conversion (nullptr being the default universe) + stage->GetRootLayer()->Save(); // Ask USD to save out the file + AiEnd(); + return 0; +} diff --git a/contrib/OpenImageIO/bin/darwin/maketx b/contrib/OpenImageIO/bin/darwin/maketx new file mode 100755 index 0000000000..c6c36f41ca Binary files /dev/null and b/contrib/OpenImageIO/bin/darwin/maketx differ diff --git a/contrib/OpenImageIO/bin/darwin/oiiotool b/contrib/OpenImageIO/bin/darwin/oiiotool new file mode 100755 index 0000000000..6f7ce57e97 Binary files /dev/null and b/contrib/OpenImageIO/bin/darwin/oiiotool differ diff --git a/contrib/OpenImageIO/bin/linux/maketx b/contrib/OpenImageIO/bin/linux/maketx new file mode 100755 index 0000000000..88faa8107c Binary files /dev/null and b/contrib/OpenImageIO/bin/linux/maketx differ diff --git a/contrib/OpenImageIO/bin/linux/oiiotool b/contrib/OpenImageIO/bin/linux/oiiotool new file mode 100755 index 0000000000..7a878720e6 Binary files /dev/null and b/contrib/OpenImageIO/bin/linux/oiiotool differ diff --git a/contrib/OpenImageIO/bin/windows/maketx.exe b/contrib/OpenImageIO/bin/windows/maketx.exe new file mode 100755 index 0000000000..f139f8d925 Binary files /dev/null and b/contrib/OpenImageIO/bin/windows/maketx.exe differ diff --git a/contrib/OpenImageIO/bin/windows/oiiotool.exe b/contrib/OpenImageIO/bin/windows/oiiotool.exe new file mode 100755 index 0000000000..225292d6b3 Binary files /dev/null and b/contrib/OpenImageIO/bin/windows/oiiotool.exe differ diff --git a/docs/Doxyfile b/docs/Doxyfile new file mode 100755 index 0000000000..966a63f022 --- /dev/null +++ b/docs/Doxyfile @@ -0,0 +1,335 @@ +# Doxyfile 1.8.13 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "Arnold USD" +PROJECT_NUMBER = 0.0.1 +PROJECT_BRIEF = "USD toolset for Arnold" +PROJECT_LOGO = +OUTPUT_DIRECTORY = build/docs +CREATE_SUBDIRS = NO +ALLOW_UNICODE_NAMES = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 4 +ALIASES = +TCL_SUBST = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +EXTENSION_MAPPING = +MARKDOWN_SUPPORT = YES +TOC_INCLUDE_HEADINGS = 0 +AUTOLINK_SUPPORT = YES +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +GROUP_NESTED_COMPOUNDS = NO +SUBGROUPING = YES +INLINE_GROUPED_CLASSES = NO +INLINE_SIMPLE_STRUCTS = NO +TYPEDEF_HIDES_STRUCT = NO +LOOKUP_CACHE_SIZE = 0 +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = YES +EXTRACT_PACKAGE = NO +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = NO +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = NO +HIDE_SCOPE_NAMES = NO +HIDE_COMPOUND_REFERENCE= NO +SHOW_INCLUDE_FILES = YES +SHOW_GROUPED_MEMB_INC = NO +FORCE_LOCAL_INCLUDES = NO +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_MEMBERS_CTORS_1ST = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +STRICT_PROTO_MATCHING = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +LAYOUT_FILE = +CITE_BIB_FILES = +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_AS_ERROR = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- +# List input directories as strings and separate them by space. +INPUT = "README.md" "LICENSE.md" "CONTRIBUTING.md" "render_delegate" "docs" +USE_MDFILE_AS_MAINPAGE = "README.md" +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.cpp \ + *.h \ + *.md \ + *.py +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +FILTER_SOURCE_PATTERNS = +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +SOURCE_TOOLTIPS = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +CLANG_ASSISTED_PARSING = NO +CLANG_OPTIONS = +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_EXTRA_STYLESHEET = +HTML_EXTRA_FILES = +HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_GAMMA = 80 +HTML_TIMESTAMP = NO +HTML_DYNAMIC_SECTIONS = NO +HTML_INDEX_NUM_ENTRIES = 100 +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_NAME = Publisher +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = +QHG_LOCATION = +GENERATE_ECLIPSEHELP = NO +ECLIPSE_DOC_ID = org.doxygen.Project +DISABLE_INDEX = NO +GENERATE_TREEVIEW = NO +ENUM_VALUES_PER_LINE = 4 +TREEVIEW_WIDTH = 250 +EXT_LINKS_IN_WINDOW = NO +FORMULA_FONTSIZE = 10 +FORMULA_TRANSPARENT = YES +USE_MATHJAX = NO +MATHJAX_FORMAT = HTML-CSS +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest +MATHJAX_EXTENSIONS = +MATHJAX_CODEFILE = +SEARCHENGINE = YES +SERVER_BASED_SEARCH = NO +EXTERNAL_SEARCH = NO +SEARCHENGINE_URL = +SEARCHDATA_FILE = searchdata.xml +EXTERNAL_SEARCH_ID = +EXTRA_SEARCH_MAPPINGS = +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4 +EXTRA_PACKAGES = +LATEX_HEADER = +LATEX_FOOTER = +LATEX_EXTRA_STYLESHEET = +LATEX_EXTRA_FILES = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +LATEX_SOURCE_CODE = NO +LATEX_BIB_STYLE = plain +LATEX_TIMESTAMP = NO +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +RTF_SOURCE_CODE = NO +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_SUBDIR = +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- +GENERATE_DOCBOOK = NO +DOCBOOK_OUTPUT = docbook +DOCBOOK_PROGRAMLISTING = NO +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +EXTERNAL_PAGES = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +MSCGEN_PATH = +DIA_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +DOT_NUM_THREADS = 0 +DOT_FONTNAME = Helvetica +DOT_FONTSIZE = 10 +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +UML_LIMIT_NUM_FIELDS = 10 +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +INTERACTIVE_SVG = NO +DOT_PATH = +DOTFILE_DIRS = +MSCFILE_DIRS = +DIAFILE_DIRS = +PLANTUML_JAR_PATH = +PLANTUML_CFG_FILE = +PLANTUML_INCLUDE_PATH = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES \ No newline at end of file diff --git a/docs/building.md b/docs/building.md new file mode 100755 index 0000000000..caae60cfbb --- /dev/null +++ b/docs/building.md @@ -0,0 +1,115 @@ +Building Arnold to USD +====================== + +# Supported Platforms + +The toolset is currently supported and tested on Windows, Linux and Mac. + +# Dependencies + +Prefer to use the same dependencies used to build USD, otherwise prefer +the versions listed in the current VFX platform. We target USD versions starting +from v19.01 up to the latest commit on the dev branch. + +Python and Boost is optional if USD was build without Python support. + +| Name | Version | Optional | +| --- | --- | --- | +| Arnold | 5.4.0.0 | | +| USD | v19.01 - dev | | +| Python | 2.7 | x | +| Boost | 1.55 (Linux), 1.61 (Mac, Windows VS 2015), 1.65.1 (Windows VS 2017) or 1.66.0 (VFX platform) | x | +| TBB | 4.4 Update 6 or 2018 (VFX platform) | | + +# Configuring build + +Builds can be configured by either creating a `custom.py` file in the root +of the cloned repository, or pass the build flags directly. The notable options +are the following. + +## Configuring Build +- MODE: Sets the compilation mode, `opt` for optimized builds, `debug` for debug builds, and `profile` for optimized builds with debug information for profiling. +- WARN_LEVEL: Warning level, `strict` enables errors for warnings, `warn-only` prints warnings and `none` turns of errors. +- COMPILER: Compiler to use. `gcc` or `clang` (default is `gcc`) on Linux and Mac, and `msvc` on Windows. +- BUILD_SCHEMAS: Wether or not to build the schemas and their wrapper. +- BUILD_RENDER_DELEGATE: Wether or not to build the hydra render delegate. +- BUILD_USD_WRITER: Wether or not to build the arnold to usd writer tool. +- BUILD_PROCEDURAL: Wether or not to build the arnold procedural. +- BUILD_TESTSUITE: Wether or not to build the testsuite. +- BUILD_DOCS: Wether or not to build the documentation. +- BUILD_FOR_KATANA: Wether or not the build is using usd libs shipped in Katana. +- BUILD_HOUDINI_TOOLS: Wether or not to build the Houdini specific tools. +- DISABLE_CXX11_ABI: Disabling the new C++ ABI introduced in GCC 5.1. + +## Configuring Dependencies +- ARNOLD_PATH: Path to the Arnold SDK. +- ARNOLD_API_INCLUDES: Path to the Arnold API include files. Set to `$ARNOLD_PATH/include` by default. +- ARNOLD_API_LIB: Path to the Arnold API Library files. Set to `$ARNOLD_PATH/bin` on Linux and Mac, and `$ARNOLD_PATH/lib` on Windows by default. +- ARNOLD_BINARIES: Path to the Arnold API Executable files. Set to `$ARNOLD_PATH/bin` by default. +- ARNOLD_PYTHON: Path to the Arnold API Python files. Set to `$ARNOLD_PATH/bin` by default. +- USD_PATH: Path to the USD Installation Root. +- USD_INCLUDE: Path to the USD Headers. Set to `$USD_PATH/include` by default. +- USD_LIB: Path to the USD Libraries. Set to `$USD_PATH/lib` by default. +- USD_BIN: Path to the USD Executables. Set to `$USD_PATH/include` by default. +- USD_BUILD_MODE: Build mode of USD. `shared_libs` is when there is a separate library for each module, `monolithic` is when all the modules are part of a single library and `static` is when there is a singular static library for all USD. Note, `static` only supported when building the procedural and the usd -> ass converter. +- USD_MONOLITHIC_LIBRARY: Name of the USD monolithic library'. By default it is `usd_ms`. +- BOOST_INCLUDE: Where to find the boost headers. By default this points inside the USD installation, and works when USD is deployed using the official build scripts. +- BOOST_LIB: Where to find the Boost Libraries. +- BOOST_LIB_NAME: Boost library name pattern. By default it is set to `boost_%s`, meaning scons will look for boost_python. +- PYTHON_INCLUDE: Where to find the Python Includes. This is only required if USD is built with Python support. See below. +- PYTHON_LIB: Where to find the Python Library. This is only required if USD is built with Python support. See below. +- PYTHON_LIB_NAME: Name of the python library. By default it is `python27`. +- USD_HAS_PYTHON_SUPPORT: Whether or not USD was built with Python support. If it was, Boost and Python dependencies are required. +- TBB_INCLUDE: Where to find TBB headers. +- TBB_LIB: Where to find TBB libraries. + +## Configuring Installation +- PREFIX: Directory to install under. True by default. +- PREFIX_PROCEDURAL: Directory to install the procedural under. True by default. +- PREFIX_RENDER_DELEGATE: Directory to install the procedural under. True by default. +- PREFIX_HEADERS: Directory to install the headers under. True by default. +- PREFIX_LIB: Directory to install the libraries under. True by default. +- PREFIX_BIN: Directory to install the binaries under. True by default. +- PREFIX_DOCS: Directory to install the documentation under. True by default. + +## Example configuration + +This builds the project on Linux, against the Distro supplied Python libraries and a monolithic USD build. + +``` +ARNOLD_PATH='/opt/autodesk/arnold-5.4.0.0' +USD_PATH='/opt/pixar/USD' +USD_HAS_PYTHON_SUPPORT=True +USD_BUILD_MODE='monolithic' +BOOST_INCLUDE='/usr/include' +PYTHON_INCLUDE='/usr/include/python2.7' +PYTHON_LIB='/usr/lib' +PYTHON_LIB_NAME='python2.7' +PREFIX='/opt/autodesk/arnold-usd' +``` + +# Building for Katana 3.2+ + +We support building against the shipped libraries in Katana and support using the Render Delegate in the Hydra viewport. The example below is for building the Render DElegate for Katana's Hydra Viewport, where Katana is installed at `/opt/Katana3.2v1`. The most important flag is `BUILD_FOR_KATANA` which changes the build on Linux to support the uniquely named (like: `Fnusd.so`) usd libraries shipped in Katana for Linux. When using a newer compiler to build the render delegate (like GCC 6.3.1 from the vfx platform), set DISABLE_CXX11_ABI to True to disable the new C++ ABI introduced in GCC 5.1, as the vfx platform suggests. + +``` +ARNOLD_PATH='/opt/autodesk/arnold-5.4.0.0' +USD_PATH='./' +USD_INCLUDE='/opt/Katana3.2v1/include' +USD_LIB='/opt/Katana3.2v1/bin' +USD_HAS_PYTHON_SUPPORT=True +BOOST_INCLUDE='/usr/include' +PYTHON_INCLUDE='/usr/include/python2.7' +PYTHON_LIB='/usr/lib' +PYTHON_LIB_NAME='python2.7' +USD_BUILD_MODE='shared_libs' +BUILD_SCHEMAS=False +BUILD_RENDER_DELEGATE=True +BUILD_PROCEDURAL=False +BUILD_TESTSUITE=False +BUILD_USD_WRITER=False +BUILD_DOCS=False +BUILD_FOR_KATANA=True +DISABLE_CXX11_ABI=True +PREFIX='/opt/autodesk/arnold-usd' +``` diff --git a/docs/conventions.md b/docs/conventions.md new file mode 100755 index 0000000000..4764d7e07c --- /dev/null +++ b/docs/conventions.md @@ -0,0 +1,178 @@ +Code Conventions +================================== + +English is the official language to use in the code and comments. Also please +use the US spelling and not the UK one (ie. *colorize*, not *colourise*). + +Use only ASCII (Latin-1, ISO-8859-1) characters anywhere in the code, +comments or file names, this means no accents and special characters. + +For Python, generally follow the [PEP-8 guidelines](http://www.python.org/dev/peps/pep-0008/). + +Use the supplied .clang-format (for clang format 7) and the scripts to format the codebase. + +## File names + +We use snake_case for file and folder names to avoid issues between windows and unix style file systems. Header files use the "h" extension, source files use "cpp". + +``` +contrib // OK +renderDelegate.h // WRONG +render_delegate.cpp // OK +render_delegate.cxx // WRONG +``` + +## Naming conventions + +#### We follow USD's naming conventions. + +#### Classes are named CamelCase, starting with a module specific prefix unless they are not in a header. Struct is used instead of a class when storing related data in a compact way, without visibility or member functions and they only need the module specific prefix if exposed in a header. + + +```cpp +// Base library +class HdArnoldLight; // OK +class MyClass; // WRONG +class myClass; // WRONG + +struct MyStruct : public HdRenderDelegate { + // ... +}; // WRONG + +struct MyOtherStruct { + float a; + int b; + double c; +} // OK +``` + +#### Functions are also CamelCase, private and protected functions on classes are prefixed with an _ . + +```cpp +// Header file +void MyFunction(); // OK +void myFunction(); // WRONG +void my_function(); // WRONG + +class HdArnoldRenderDelegate { +public: + void MyFunction(); // OK +private: + void MyOtherFunction(); // WRONG + void _MyFunction(); // OK +}; +``` + +#### Source only functions and structs are placed in an anonymous namespace to limit symbols to compilation units and source only functions are prefixed with an _ . Anoymous namespaces do NOT increase identation tot he right. + +```cpp +// Source file + +namespace { + +void MyFunction() +{ + // ... +} // WRONG + +void _MyFunction() +{ + // ... +} // OK + +} + +``` + +#### Variables are camelCase, class variables are prefixed with an _ . Struct variables are not prefixed with an _ . + +```cpp +int myVariable; // OK +int my_variable; // WRONG + +class HdArnoldRenderDelegate { +private: + int myVariable; // WRONG + int _myVariable; // OK +}; + +struct MyStruct { + int _myVariable; // WRONG + int myVariable; // OK +}; +``` + +#### Macros and enums are all upper case. + +```cpp +#define UPDATE_UNDEFINED 0 +#define UPDATE_CAMERA 1 + +enum PartitionType +{ + POINTS = 0, + PRIMITIVES, + DETAIL +}; +``` + + +## Coding style + +#### We use C++11 to follow USD's choice of standard and respect the [C++ core guidelines](http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines.html). + +#### Some highlights. + +#### Maximum column width for source files is 120. Use short lines (~80 to follow USD's convention), unless indenting becomes hard to follow. + +#### There is no space between the name of a method or function and its parenthesis, neither between the parenthesis and the arguments. + +```cpp +myFunction(a, b); // OK +myFunction (a, b); // wrong +myFunction( a, b ); // wrong +``` + +#### End source files with an empty line. + +#### Use const and constexpr wherever possible. + +#### Use nullptr in place of NULL or 0 for pointers. + +```cpp +A* a = nullptr; // OK +B* b = 0; // WRONG +C* c = NULL; // WRONG +``` + +#### Use override for class functions. + +#### Use C++ style casting. + +#### Use C++ notation for include files. + +```cpp +#include // OK +#include // WRONG +``` + +#### Use C++ comments (`//`), not C comments (`/* ... \*\/`). There must be a space following the `//`. + +```cpp +// I am a nice comment. +//But I am not. +/* I'm ugly too. */ +``` + +#### Indent with four (4) real spaces, no tabs. + +#### Brackets are always required for every block of code, to avoid possible mistakes, like problems with macros. + +```cpp +if (statement) + OneLineFunction(); // WRONG + +if (statement) { + OneLineFunction(); // OK +} +``` diff --git a/docs/documenting.md b/docs/documenting.md new file mode 100755 index 0000000000..ea16419428 --- /dev/null +++ b/docs/documenting.md @@ -0,0 +1,57 @@ +Documentation rules +=================== + +Documentation is put in special comments, directly in the code so that you can +refer to and update the documentation while you're parsing or editing the code. +Special pages, such as this one, can be created as .dox files. This also +implies the documentation is version controlled along with the code. Doxygen +can then automatically generate HTML files, LaTeX, CHM files or other formats. + +Please refer to the [Doxygen manual](http://www.doxygen.org/manual.html) for +details about Doxygen tags and syntax. + +### Doxygen conventions + +Doxygen allows different styles to document the code but we'll stick to these +conventions, chosen for elegance and simplicity: + +- Doxygen commands and tags are prefixed with an at-sign (@@) + +- The first line, until the first dot or blank line, of a Doxygen comment +will be used as the brief one-line description (`JAVADOC_AUTOBRIEF` and +`QT_AUTOBRIEF` are on). + +### Documentation guidelines + +Always precede classes, methods and functions with a Doxygen-style comment. +For classes, describe its responsabilities and dependencies. For methods and +functions, describe what the function does *and* describe each individual +parameter, as well as the return value. Follow the syntax in this example: + +``` +/// Short description in one phrase (in this case: Add two numbers together). +/// +/// Optionally, here goes a much more detailed description of the function. +/// This longer description can spawn multiple lines, include code samples, etc. +/// +/// @param a This is the first floating point number to be added +/// @param b And this is the second number +/// @return The sum a + b +float myAddFunction(float a, float b) +{ + // ... +} +``` + +Always add a short description for each header file after the license to +explain its purpose and use the `\@file` tag to tag the file for doxygen. + +### Documenting C++ code + +- Use the three slashes for C++ Doxygen comments (`///`). After member +documentation is done with `///<`. + +- the first sentence will be the short description of what you are documenting. +The first sentence is ended by a dot (`.`) or a blank line. + +An example of a well documented header file is: renderDelegate/nodes/nodes.h \ No newline at end of file diff --git a/procedural/SConscript b/procedural/SConscript new file mode 100755 index 0000000000..157087f216 --- /dev/null +++ b/procedural/SConscript @@ -0,0 +1,95 @@ +# vim: filetype=python +# Copyright 2019 Autodesk, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +## load our own python modules +from utils import system +from utils.build_tools import find_files_recursive + +import os + +# import build env +Import('env') +myenv = env.Clone() + +src_proc_dir = os.path.join(myenv['ROOT_DIR'], 'procedural') +source_files = [os.path.join('main.cpp')] +src_translator_dir = os.path.join(myenv['ROOT_DIR'], 'translator', 'reader') + +# Compiler flags +if not system.IS_WINDOWS: + myenv.Append(CXXFLAGS = Split('-fPIC -Wno-deprecated-register')) + + +# Include paths +includePaths = [ + '.', + src_translator_dir +] +myenv.Append(CPPPATH = includePaths) + +myenv.Append(LIBS = ['ai']) + +usd_deps = [] + +if myenv['USD_BUILD_MODE'] == 'monolithic': + usd_deps = [ + myenv['USD_MONOLITHIC_LIBRARY'], + 'tbb', + ] +elif myenv['USD_BUILD_MODE'] == 'static': + # static builds rely on a monolithic static library + if system.IS_WINDOWS: + usd_deps = [ + '-WHOLEARCHIVE:libusd_m', + 'Ws2_32', + 'Dbghelp', + 'Shlwapi', + 'advapi32' + ] + if not myenv['TBB_STATIC']: + usd_deps += ['tbb'] + else: + whole_archives = '%s/libusd_m.a' % myenv.subst(myenv['USD_LIB']) + if myenv['TBB_STATIC']: + whole_archives += ',%s/libtbb.a' % myenv.subst(myenv['TBB_LIB']) + else: + usd_deps = ['tbb'] + + if system.IS_LINUX: + myenv.Append(LINKFLAGS=['-Wl,--whole-archive,%s,--no-whole-archive' % whole_archives]) + else: + myenv.Append(LINKFLAGS=['-Wl,-all_load,%s,-noall_load' % whole_archives]) +else: # shared libs + usd_deps = [ + 'sdf', + 'tf', + 'usd', + 'ar', + 'usdGeom', + 'usdShade', + 'vt', + 'usdLux', + ] + +translatorLibPath = os.path.abspath(os.path.join(myenv['BUILD_BASE_DIR'], 'translator')) +myenv.Append(LIBPATH = [translatorLibPath]) +myenv.Append(LIBS = ['usd_translator']) + +myenv.Append(LIBS = usd_deps) +if myenv['USD_HAS_PYTHON_SUPPORT']: + myenv.Append(LIBS = [myenv['PYTHON_LIB_NAME'], myenv['BOOST_LIB_NAME'] % 'python']) + +# Build shared library for the Alembic procedural +USD = myenv.SharedLibrary('usd_proc', source_files, SHLIBPREFIX='') +Return('USD') diff --git a/procedural/main.cpp b/procedural/main.cpp new file mode 100755 index 0000000000..bc0e0c6bac --- /dev/null +++ b/procedural/main.cpp @@ -0,0 +1,138 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include "reader.h" + +#if defined(_DARWIN) +#include +#endif + +//-************************************************************************* +// Code for the Arnold procedural node loading USD files + +AI_PROCEDURAL_NODE_EXPORT_METHODS(UsdProceduralMethods); + +node_parameters +{ + AiParameterStr("filename", ""); + AiParameterStr("object_path", ""); + AiParameterFlt("frame", 0.0); + AiParameterBool("debug", false); + AiParameterInt("threads", 1); + AiParameterArray("overrides", AiArray(0, 1, AI_TYPE_STRING)); +} + +procedural_init +{ + UsdArnoldReader *data = new UsdArnoldReader(); + *user_ptr = data; + + std::string filename(AiNodeGetStr(node, "filename")); + if (filename.empty()) { + return false; + } + std::string objectPath(AiNodeGetStr(node, "object_path")); + data->setProceduralParent(node); + data->setFrame(AiNodeGetFlt(node, "frame")); + data->setDebug(AiNodeGetBool(node, "debug")); + data->setThreadCount(AiNodeGetInt(node, "threads")); + + AtNode *renderCam = AiUniverseGetCamera(); + if (renderCam && + (AiNodeGetFlt(renderCam, AtString("shutter_start")) < AiNodeGetFlt(renderCam, AtString("shutter_end")))) { + float motion_start = AiNodeGetFlt(renderCam, AtString("shutter_start")); + float motion_end = AiNodeGetFlt(renderCam, AtString("shutter_end")); + data->setMotionBlur((motion_start < motion_end), motion_start, motion_end); + } else { + data->setMotionBlur(false); + } + + // export the USD file + data->read(filename, AiNodeGetArray(node, "overrides"), objectPath); + return 1; +} + +//-************************************************************************* + +procedural_cleanup +{ + delete reinterpret_cast(user_ptr); + return 1; +} + +//-************************************************************************* + +procedural_num_nodes +{ + UsdArnoldReader *data = reinterpret_cast(user_ptr); + if (data) { + return data->getNodes().size(); + } + return 0; +} + +//-************************************************************************* + +procedural_get_node +{ + UsdArnoldReader *data = reinterpret_cast(user_ptr); + if (data) { + return data->getNodes()[i]; + } + return NULL; +} + +#if defined(_DARWIN) +std::string USDLibraryPath() +{ + Dl_info info; + if (dladdr("USDLibraryPath", &info)) + { + std::string path = info.dli_fname; + return path; + } + + return std::string(); +} +#endif + +node_loader +{ + if (i > 0) { + return false; + } + + node->methods = UsdProceduralMethods; + node->output_type = AI_TYPE_NONE; + node->name = AtString("usd"); + node->node_type = AI_NODE_SHAPE_PROCEDURAL; + strcpy(node->version, AI_VERSION); + + /* Fix the pre-10.13 OSX crashes at shutdown (#8866). Manually dlopening usd + * prevents it from being unloaded since loads are reference counted + * see : https://github.com/openssl/openssl/issues/653#issuecomment-206343347 + * https://github.com/jemalloc/jemalloc/issues/1122 + */ +#if defined(_DARWIN) + const auto result = dlopen(USDLibraryPath().c_str(), RTLD_LAZY | RTLD_GLOBAL | RTLD_NODELETE); + if (!result) + AiMsgWarning("[USD] failed to re-load usd_proc.dylib. Crashes might happen on pre-10.13 OSX systems: %s\n", dlerror()); +#endif + return true; +} diff --git a/render_delegate/SConscript b/render_delegate/SConscript new file mode 100755 index 0000000000..3ecc0784db --- /dev/null +++ b/render_delegate/SConscript @@ -0,0 +1,90 @@ +# Copyright 2019 Autodesk, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os +from utils import system, build_tools + +Import('env') +local_env = env.Clone() + +from utils import configure + +src_dir = os.path.join(env['ROOT_DIR'], 'render_delegate') +source_files = [ + 'config.cpp', + 'constant_strings.cpp', + 'debug_codes.cpp', + 'instancer.cpp', + 'light.cpp', + 'material.cpp', + 'mesh.cpp', + 'openvdb_asset.cpp', + 'points.cpp', + 'render_buffer.cpp', + 'render_delegate.cpp', + 'render_param.cpp', + 'render_pass.cpp', + 'renderer_plugin.cpp', + 'shape.cpp', + 'utils.cpp', + 'volume.cpp', + os.path.join('nodes', 'driver.cpp'), + os.path.join('nodes', 'nodes.cpp'), +] + +if system.os != 'windows': + local_env.Append(CXXFLAGS = Split('-fPIC')) + +if local_env['USD_1910_UPDATED_COMPOSITOR']: + local_env.Append(CPPDEFINES=['USD_1910_UPDATED_COMPOSITOR']) + +if local_env['BUILD_HOUDINI_TOOLS']: + local_env.Append(CPPDEFINES=['BUILD_HOUDINI_TOOLS']) + +local_env.Append(CPPDEFINES=['HDARNOLD_EXPORTS']) +local_env.Append(CPPPATH = [os.path.join(env['ROOT_DIR'], env['BUILD_BASE_DIR'], 'render_delegate')]) +local_env.Append(LIBS = ['ai']) + +if local_env['USD_BUILD_MODE'] == 'monolithic': + usd_deps = [ + local_env['USD_MONOLITHIC_LIBRARY'], + 'tbb', + ] +else: + usd_libs = [ + 'arch', + 'plug', + 'tf', + 'vt', + 'gf', + 'work', + 'hf', + 'hd', + 'hdx', + 'sdf', + 'usdImaging', + 'usdLux', + 'pxOsd', + ] + + usd_deps = ['tbb'] + usd_libs, usd_sources = build_tools.link_usd_libraries(local_env, usd_libs) + usd_deps = usd_deps + usd_libs + source_files = source_files + usd_sources + +local_env.Append(LIBS = usd_deps) +if local_env['USD_HAS_PYTHON_SUPPORT']: + local_env.Append(LIBS = [local_env['PYTHON_LIB_NAME'], local_env['BOOST_LIB_NAME'] % 'python']) + +RENDERDELEGATE = local_env.SharedLibrary('hdArnold', source_files, SHLIBPREFIX='') +Return('RENDERDELEGATE') diff --git a/render_delegate/api.h b/render_delegate/api.h new file mode 100755 index 0000000000..0a3177e679 --- /dev/null +++ b/render_delegate/api.h @@ -0,0 +1,52 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/// @file api.h +/// +/// API definitions for exports and imports. +#pragma once + +#include +#include + +#if defined(PXR_STATIC) +#define HDARNOLD_API +#define HDARNOLD_API_TEMPLATE_CLASS(...) +#define HDARNOLD_API_TEMPLATE_STRUCT(...) +#define HDARNOLD_LOCAL +#else +#if defined(HDARNOLD_EXPORTS) +#define HDARNOLD_API ARCH_EXPORT +#define HDARNOLD_API_TEMPLATE_CLASS(...) ARCH_EXPORT_TEMPLATE(class, __VA_ARGS__) +#define HDARNOLD_API_TEMPLATE_STRUCT(...) ARCH_EXPORT_TEMPLATE(struct, __VA_ARGS__) +#else +#define HDARNOLD_API ARCH_IMPORT +#define HDARNOLD_API_TEMPLATE_CLASS(...) ARCH_IMPORT_TEMPLATE(class, __VA_ARGS__) +#define HDARNOLD_API_TEMPLATE_STRUCT(...) ARCH_IMPORT_TEMPLATE(struct, __VA_ARGS__) +#endif +#define HDARNOLD_LOCAL ARCH_HIDDEN +#endif diff --git a/render_delegate/config.cpp b/render_delegate/config.cpp new file mode 100755 index 0000000000..e14459f659 --- /dev/null +++ b/render_delegate/config.cpp @@ -0,0 +1,129 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "config.h" + +#include +#include + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +TF_INSTANTIATE_SINGLETON(HdArnoldConfig); + +TF_DEFINE_ENV_SETTING(HDARNOLD_bucket_size, 24, "Bucket size."); + +TF_DEFINE_ENV_SETTING(HDARNOLD_abort_on_error, false, "Abort on error."); + +TF_DEFINE_ENV_SETTING(HDARNOLD_log_verbosity, 2, "Control the amount of log output. (0-5)"); + +TF_DEFINE_ENV_SETTING(HDARNOLD_log_file, "", "Set a filepath to output logging information to."); + +// These two are "secret", in the sense that they're not exposed via +// HdArnoldRenderDelegate::GetRenderSettingDescriptors, as they would be too confusing / +// advanced to expose via a GUI to artists. However, they're settable via env vars if you +// really need exact control. See ai_msg.h for possible values / flags. +TF_DEFINE_ENV_SETTING(HDARNOLD_log_flags_console, -1, "Override logging flags for console output, if non-negative."); + +TF_DEFINE_ENV_SETTING(HDARNOLD_log_flags_file, -1, "Override logging flags for file output, if non-negative."); + +TF_DEFINE_ENV_SETTING(HDARNOLD_AA_samples, 10, "Number of AA samples by default."); + +TF_DEFINE_ENV_SETTING(HDARNOLD_GI_diffuse_samples, 1, "Number of diffuse samples by default."); + +TF_DEFINE_ENV_SETTING(HDARNOLD_GI_specular_samples, 1, "Number of specular samples by default."); + +TF_DEFINE_ENV_SETTING(HDARNOLD_GI_transmission_samples, 1, "Number of transmission samples by default."); + +TF_DEFINE_ENV_SETTING(HDARNOLD_GI_sss_samples, 1, "Number of sss samples by default."); + +TF_DEFINE_ENV_SETTING(HDARNOLD_GI_volume_samples, 1, "Number of volume samples by default."); + +TF_DEFINE_ENV_SETTING(HDARNOLD_threads, -1, "Number of Threads for CPU rendering by default."); + +TF_DEFINE_ENV_SETTING(HDARNOLD_GI_diffuse_depth, 1, "Diffuse ray depth by default."); + +TF_DEFINE_ENV_SETTING(HDARNOLD_GI_specular_depth, 1, "Diffuse ray depth by default."); + +TF_DEFINE_ENV_SETTING(HDARNOLD_enable_progressive_render, true, "Enable progressive render."); + +TF_DEFINE_ENV_SETTING(HDARNOLD_progressive_min_AA_samples, -4, "Minimum AA samples for progressive rendering."); + +TF_DEFINE_ENV_SETTING(HDARNOLD_enable_adaptive_sampling, false, "Enable adaptive sapmling."); + +TF_DEFINE_ENV_SETTING(HDARNOLD_enable_gpu_rendering, false, "Enable gpu rendering."); + +// This macro doesn't support floating point values. +TF_DEFINE_ENV_SETTING(HDARNOLD_shutter_start, "-0.25f", "Shutter start for the camera."); + +TF_DEFINE_ENV_SETTING(HDARNOLD_shutter_end, "0.25f", "Shutter end for the camera."); + +TF_DEFINE_ENV_SETTING(HDARNOLD_interactive_target_fps, "30.0", "Interactive target fps for progressive rendering."); + +TF_DEFINE_ENV_SETTING( + HDARNOLD_interactive_target_fps_min, "20.0", "Min interactive target fps for progressive rendering."); + +TF_DEFINE_ENV_SETTING(HDARNOLD_interactive_fps_min, "5.0", "Minimum fps for progressive rendering."); + +TF_DEFINE_ENV_SETTING(HDARNOLD_profile_file, "", "Output file for profiling information.") + +HdArnoldConfig::HdArnoldConfig() +{ + bucket_size = std::max(1, TfGetEnvSetting(HDARNOLD_bucket_size)); + abort_on_error = TfGetEnvSetting(HDARNOLD_abort_on_error); + log_verbosity = std::max(0, std::min(7, TfGetEnvSetting(HDARNOLD_log_verbosity))); + log_file = TfGetEnvSetting(HDARNOLD_log_file); + log_flags_console = TfGetEnvSetting(HDARNOLD_log_flags_console); + log_flags_file = TfGetEnvSetting(HDARNOLD_log_flags_file); + threads = TfGetEnvSetting(HDARNOLD_threads); + AA_samples = TfGetEnvSetting(HDARNOLD_AA_samples); + GI_diffuse_samples = std::max(0, TfGetEnvSetting(HDARNOLD_GI_diffuse_samples)); + GI_specular_samples = std::max(0, TfGetEnvSetting(HDARNOLD_GI_specular_samples)); + GI_transmission_samples = std::max(0, TfGetEnvSetting(HDARNOLD_GI_transmission_samples)); + GI_sss_samples = std::max(0, TfGetEnvSetting(HDARNOLD_GI_sss_samples)); + GI_volume_samples = std::max(0, TfGetEnvSetting(HDARNOLD_GI_volume_samples)); + GI_diffuse_depth = std::max(0, TfGetEnvSetting(HDARNOLD_GI_diffuse_depth)); + GI_specular_depth = std::max(0, TfGetEnvSetting(HDARNOLD_GI_specular_depth)); + enable_progressive_render = TfGetEnvSetting(HDARNOLD_enable_progressive_render); + progressive_min_AA_samples = TfGetEnvSetting(HDARNOLD_progressive_min_AA_samples); + enable_adaptive_sampling = TfGetEnvSetting(HDARNOLD_enable_adaptive_sampling); + enable_gpu_rendering = TfGetEnvSetting(HDARNOLD_enable_gpu_rendering); + shutter_start = static_cast(std::atof(TfGetEnvSetting(HDARNOLD_shutter_start).c_str())); + shutter_end = static_cast(std::atof(TfGetEnvSetting(HDARNOLD_shutter_end).c_str())); + interactive_target_fps = + std::max(1.0f, static_cast(std::atof(TfGetEnvSetting(HDARNOLD_interactive_target_fps).c_str()))); + interactive_target_fps_min = + std::max(1.0f, static_cast(std::atof(TfGetEnvSetting(HDARNOLD_interactive_target_fps_min).c_str()))); + interactive_fps_min = + std::max(1.0f, static_cast(std::atof(TfGetEnvSetting(HDARNOLD_interactive_fps_min).c_str()))); + profile_file = TfGetEnvSetting(HDARNOLD_profile_file); +} + +const HdArnoldConfig& HdArnoldConfig::GetInstance() { return TfSingleton::GetInstance(); } + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/config.h b/render_delegate/config.h new file mode 100755 index 0000000000..de378012f2 --- /dev/null +++ b/render_delegate/config.h @@ -0,0 +1,162 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/// @file config.h +/// +/// Configuration settings for the Render Delegate. +/// +/// Access configuration settings not available through the public interface. +#pragma once + +#include + +#include + +#include "api.h" + +PXR_NAMESPACE_OPEN_SCOPE + +/// Class that holds the global configuration values for the Render Delegate. +class HdArnoldConfig { +public: + /// Return an instance of HdArnoldConfig. + HDARNOLD_API + static const HdArnoldConfig& GetInstance(); + + /// Use HDARNOLD_bucket_size to set the value. + /// + int bucket_size; ///< Bucket size for non-progressive renders. + + /// Use HDARNOLD_abort_on_error to set the value. + /// + bool abort_on_error; ///< Abort render if any errors occur. + + /// Use HDARNOLD_log_verbosity to set the value. + /// + int log_verbosity; ///< Control how many messages are output (0-5). + + /// Use HDARNOLD_log_file to set the value. + /// + std::string log_file; ///< Set a filepath to output logging information to. + + /// Use HDARNOLD_log_flags_console to set the value. + /// + int log_flags_console; ///< Override logging flags for console output. + + /// Use HDARNOLD_log_flags_file to set the value. + /// + int log_flags_file; ///< Override logging flags for file output. + + /// Use HDARNOLD_threads to set the value. + /// + int threads; ///< Number of threads to use for CPU rendering. + + /// Use HDARNOLD_GI_diffuse_samples to set the value. + /// + int GI_diffuse_samples; ///< Number of diffuse samples. + + /// Use HDARNOLD_GI_specular_samples to set the value. + /// + int GI_specular_samples; ///< Number of specular samples. + + /// Use HDARNOLD_GI_transmission_samples to set the value. + /// + int GI_transmission_samples; ///< Number of transmission samples. + + /// Use HDARNOLD_GI_sss_samples to set the value. + /// + int GI_sss_samples; ///< Number of sss samples. + + /// Use HDARNOLD_GI_volume_samples to set the value. + /// + int GI_volume_samples; ///< Number of volume samples. + + /// Use HDARNOLD_AA_samples to set the value. + /// + int AA_samples; ///< Initial setting for AA samples. + + /// Use HDARNOLD_GI_diffuse_depth to set the value. + /// + int GI_diffuse_depth; ///< Initial setting for Diffuse Depth. + + /// Use HDARNOLD_GI_specular_depth to set the value. + /// + int GI_specular_depth; ///< Initial setting for Specular Depth. + + /// Use HDARNOLD_enable_progressive_render to set the value. + /// + bool enable_progressive_render; ///< Enables progressive rendering. + + /// Use HDARNOLD_progressive_min_AA_samples to set the value. + /// + bool progressive_min_AA_samples; + + /// Use HDARNOLD_enable_adaptive_sampling to set the value. + /// + bool enable_adaptive_sampling; ///< Enables adaptive sampling. + + /// Use HDARNOLD_enable_gpu_rendering to set the value. + /// + bool enable_gpu_rendering; ///< Enables gpu rendering. + + /// Use HDARNOLD_shutter_start to set the value. + /// + float shutter_start; ///< Shutter start for the camera. + + /// Use HDARNOLD_shutter_end to set the value. + /// + float shutter_end; ///< Shutter end for the camera. + + /// Use HDARNOLD_interactive_target_fps to set the value. + /// + float interactive_target_fps; ///< Interactive Target FPS. + + /// Use HDARNOLD_interactive_target_fps_min to set the value. + /// + float interactive_target_fps_min; ///< Interactive Target FPS Minimum. + + /// Use HDARNOLD_interactive_fps_min to set value. + /// + float interactive_fps_min; ///< Interactive FPS Minimum. + + /// Use HDARNOLD_profile_file to set the value. + /// + std::string profile_file; ///< Output file for profiling data. + +private: + /// Constructor for reading the values from the environment variables. + HDARNOLD_API + HdArnoldConfig(); + ~HdArnoldConfig() = default; + HdArnoldConfig(const HdArnoldConfig&) = delete; + HdArnoldConfig(HdArnoldConfig&&) = delete; + HdArnoldConfig& operator=(const HdArnoldConfig&) = delete; + + friend class TfSingleton; +}; + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/constant_strings.cpp b/render_delegate/constant_strings.cpp new file mode 100755 index 0000000000..eb9a5ddd56 --- /dev/null +++ b/render_delegate/constant_strings.cpp @@ -0,0 +1,16 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#define EXPAND_HDARNOLD_STRINGS +#include "constant_strings.h" diff --git a/render_delegate/constant_strings.h b/render_delegate/constant_strings.h new file mode 100755 index 0000000000..1d443249b0 --- /dev/null +++ b/render_delegate/constant_strings.h @@ -0,0 +1,246 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/// @file astrings.h +/// +/// File holding shared, constant definitions of AtString instances. +/// +/// Defining EXPAND_HDARNOLD_STRINGS before including atstrings.h will not only +/// declare but also define the AtString instances. +#pragma once + +#include "api.h" + +#include + +#include +#include + +PXR_NAMESPACE_OPEN_SCOPE + +namespace str { + +#ifdef EXPAND_HDARNOLD_STRINGS +#define ASTR(x) \ + extern const AtString x; \ + const AtString x(#x); \ + extern const TfToken t_##x; \ + const TfToken t_##x(#x) +#define ASTR2(x, y) \ + extern const AtString x; \ + const AtString x(y); \ + extern const TfToken t_##x; \ + const TfToken t_##x(y) +#else +#define ASTR(x) \ + extern const AtString x; \ + extern const TfToken t_##x +#define ASTR2(x, y) \ + extern const AtString x; \ + extern const TfToken t_##x +#endif + +ASTR2(defaultStr, "default"); +ASTR2(renderPassCamera, "HdArnoldRenderPass_camera"); +ASTR2(renderPassFilter, "HdArnoldRenderPass_beautyFilter"); +ASTR2(renderPassClosestFilter, "HdArnoldRenderPass_closestFilter"); +ASTR2(renderPassDriver, "HdArnoldRenderPass_driver"); + +ASTR(AA_sample_clamp); +ASTR(AA_sample_clamp_affects_aovs); +ASTR(AA_samples); +ASTR(AA_samples_max); +ASTR(AA_seed); +ASTR(abort_on_error); +ASTR(abort_on_license_fail); +ASTR(angular); +ASTR(attribute); +ASTR(auto_transparency_depth); +ASTR(base); +ASTR(base_color); +ASTR(bucket_scanning); +ASTR(bucket_size); +ASTR(camera); +ASTR(catclark); +ASTR(clearcoat); +ASTR(clearcoatRoughness); +ASTR(closest_filter); +ASTR(coat); +ASTR(coat_roughness); +ASTR(color); +ASTR(color_mode); +ASTR(CPU); +ASTR(crease_idxs); +ASTR(crease_sharpness); +ASTR(cylinder_light); +ASTR(diffuseColor); +ASTR(disk_light); +ASTR(disp_map); +ASTR(distant_light); +ASTR(emission); +ASTR(emission_color); +ASTR(emissiveColor); +ASTR(enable_adaptive_sampling); +ASTR(enable_dependency_graph); +ASTR(enable_dithered_sampling); +ASTR(enable_gpu_rendering); +ASTR(enable_new_point_light_sampler); +ASTR(enable_new_quad_light_sampler); +ASTR(enable_procedural_cache); +ASTR(enable_progressive_pattern); +ASTR(enable_progressive_render); +ASTR(fallback); +ASTR(file); +ASTR(filename); +ASTR(flat); +ASTR(format); +ASTR(fov); +ASTR(fps); +ASTR(frame); +ASTR(gaussian_filter); +ASTR(GI_diffuse_depth); +ASTR(GI_diffuse_samples); +ASTR(GI_specular_depth); +ASTR(GI_specular_samples); +ASTR(GI_sss_samples); +ASTR(GI_total_depth); +ASTR(GI_transmission_depth); +ASTR(GI_transmission_samples); +ASTR(GI_volume_depth); +ASTR(GI_volume_samples); +ASTR(ginstance); +ASTR(GPU); +ASTR(grids); +ASTR(id); +ASTR(ignore_atmosphere); +ASTR(ignore_bump); +ASTR(ignore_displacement); +ASTR(ignore_dof); +ASTR(ignore_lights); +ASTR(ignore_motion); +ASTR(ignore_motion_blur); +ASTR(ignore_operators); +ASTR(ignore_shaders); +ASTR(ignore_shadows); +ASTR(ignore_smoothing); +ASTR(ignore_sss); +ASTR(ignore_subdivision); +ASTR(ignore_textures); +ASTR(image); +ASTR(indirect_sample_clamp); +ASTR(interactive_fps_min); +ASTR(interactive_target_fps); +ASTR(interactive_target_fps_min); +ASTR(ior); +ASTR(latlong); +ASTR(log_file); +ASTR(log_flags_console); +ASTR(log_flags_file); +ASTR(log_verbosity); +ASTR(matrix); +ASTR(metallic); +ASTR(metalness); +ASTR(mirrored_ball); +ASTR(missing_texture_color); +ASTR(name); +ASTR(node); +ASTR(none); +ASTR(normal); +ASTR(normal_nonexistant_rename); +ASTR(nsides); +ASTR(opacity); +ASTR(opaque); +ASTR(outputs); +ASTR(parallel_node_init); +ASTR(persp_camera); +ASTR(pin_threads); +ASTR(pixel_aspect_ratio); +ASTR(points); +ASTR(point_light); +ASTR(polymesh); +ASTR(profile_file); +ASTR(progressive); +ASTR(progressive_min_AA_samples); +ASTR(progressive_show_all_outputs); +ASTR(quad_light); +ASTR(radius); +ASTR(reference_time); +ASTR(region_max_x); +ASTR(region_max_y); +ASTR(region_min_x); +ASTR(region_min_y); +ASTR(render_device); +ASTR(roughness); +ASTR(shade_mode); +ASTR(shader); +ASTR(shutter_end); +ASTR(shutter_start); +ASTR(sidedness); +ASTR(skydome_light); +ASTR(specular); +ASTR(specular_color); +ASTR(specular_IOR); +ASTR(specular_roughness); +ASTR(specularColor); +ASTR(st); +ASTR(standard_surface); +ASTR(step_size); +ASTR(subdiv_iterations); +ASTR(subdiv_type); +ASTR(texture_accept_unmipped); +ASTR(texture_accept_untiled); +ASTR(texture_automip); +ASTR(texture_autotile); +ASTR(texture_conservative_lookups); +ASTR(texture_failure_retries); +ASTR(texture_max_open_files); +ASTR(texture_per_file_stats); +ASTR(tflip); +ASTR(thread_priority); +ASTR(threads); +ASTR(UsdPreviewSurface); +ASTR(UsdPrimvarReader_float); +ASTR(UsdPrimvarReader_float2); +ASTR(UsdPrimvarReader_float3); +ASTR(UsdPrimvarReader_float4); +ASTR(UsdPrimvarReader_int); +ASTR(UsdPrimvarReader_normal); +ASTR(UsdPrimvarReader_point); +ASTR(UsdPrimvarReader_string); +ASTR(UsdPrimvarReader_vector); +ASTR(UsdUVTexture); +ASTR(user_data_float); +ASTR(user_data_int); +ASTR(user_data_rgb); +ASTR(user_data_rgba); +ASTR(user_data_string); +ASTR(useSpecularWorkflow); +ASTR(utility); +ASTR(uv); +ASTR(uvcoords); +ASTR(uvidxs); +ASTR(uvlist); +ASTR(varname); +ASTR(vidxs); +ASTR(visibility); +ASTR(vlist); +ASTR(volume); +ASTR(xres); +ASTR(yres); + +#undef ASTR +#undef ASTR2 + +} // namespace str + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/debug_codes.cpp b/render_delegate/debug_codes.cpp new file mode 100755 index 0000000000..268162d737 --- /dev/null +++ b/render_delegate/debug_codes.cpp @@ -0,0 +1,43 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "debug_codes.h" + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +TF_REGISTRY_FUNCTION(TfDebug) +{ + TF_DEBUG_ENVIRONMENT_SYMBOL( + HDARNOLD_MATERIAL, + "Print info about material translation for the arnold hydra render " + "delegate"); +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/debug_codes.h b/render_delegate/debug_codes.h new file mode 100755 index 0000000000..ee086a344e --- /dev/null +++ b/render_delegate/debug_codes.h @@ -0,0 +1,42 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +// clang-format off +TF_DEBUG_CODES( + HDARNOLD_MATERIAL +); +// clang-format on + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/hdarnold.h b/render_delegate/hdarnold.h new file mode 100755 index 0000000000..ec413e78cb --- /dev/null +++ b/render_delegate/hdarnold.h @@ -0,0 +1,33 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include "../arnold_usd.h" + +/// From 19.05. +#if USED_USD_VERSION_GREATER_EQ(19, 5) +/// Hydra has the new GetInstancerTransform API. +#define USD_HAS_NEW_INSTANCER_TRANSFORM +#endif + +#if USED_USD_VERSION_GREATER_EQ(19, 10) +/// Hydra has the new material terminal tokens. +#define USD_HAS_NEW_MATERIAL_TERMINAL_TOKENS +/// Hydra has the new renderer plugin base class +#define USD_HAS_NEW_RENDERER_PLUGIN +/// Hydra has the new compositor functions +#ifdef USD_1910_UPDATED_COMPOSITOR +#define USD_HAS_UPDATED_COMPOSITOR +#endif +#endif diff --git a/render_delegate/instancer.cpp b/render_delegate/instancer.cpp new file mode 100755 index 0000000000..b763ea485f --- /dev/null +++ b/render_delegate/instancer.cpp @@ -0,0 +1,179 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "instancer.h" + +#include +#include +#include + +PXR_NAMESPACE_OPEN_SCOPE + +// clang-format off +TF_DEFINE_PRIVATE_TOKENS(_tokens, + (instanceTransform) + (rotate) + (scale) + (translate) +); +// clang-format on + +namespace { + +template +inline void _UpdateInstancePrimvar( + HdSceneDelegate* delegate, int dirtyBits, const SdfPath& id, const HdPrimvarDescriptorVector& primvars, + const TfToken& primvar, VtArray& out) +{ + auto found = false; + for (const auto& pv : primvars) { + if (pv.name == primvar) { + found = true; + break; + } + } + if (!found) { + return; + } + if (HdChangeTracker::IsPrimvarDirty(dirtyBits, id, primvar)) { + auto value = delegate->Get(id, primvar); + if (value.IsEmpty() || !value.IsHolding>()) { + out.clear(); + } else { + out = value.UncheckedGet>(); + } + } +} + +} // namespace + +HdArnoldInstancer::HdArnoldInstancer( + HdArnoldRenderDelegate* renderDelegate, HdSceneDelegate* sceneDelegate, const SdfPath& id, + const SdfPath& parentInstancerId) + : HdInstancer(sceneDelegate, id, parentInstancerId), _delegate(renderDelegate) +{ +} + +void HdArnoldInstancer::_SyncPrimvars() +{ + auto& changeTracker = GetDelegate()->GetRenderIndex().GetChangeTracker(); + const auto& id = GetId(); + + auto dirtyBits = changeTracker.GetInstancerDirtyBits(id); + if (!HdChangeTracker::IsAnyPrimvarDirty(dirtyBits, id)) { + return; + } + + std::lock_guard lock(_mutex); + dirtyBits = changeTracker.GetInstancerDirtyBits(id); + + if (!HdChangeTracker::IsAnyPrimvarDirty(dirtyBits, id)) { + return; + } + + auto* delegate = GetDelegate(); + const auto primvars = delegate->GetPrimvarDescriptors(id, HdInterpolationInstance); + _UpdateInstancePrimvar(delegate, dirtyBits, id, primvars, _tokens->translate, _translate); + _UpdateInstancePrimvar(delegate, dirtyBits, id, primvars, _tokens->rotate, _rotate); + _UpdateInstancePrimvar(delegate, dirtyBits, id, primvars, _tokens->scale, _scale); + _UpdateInstancePrimvar(delegate, dirtyBits, id, primvars, _tokens->instanceTransform, _instanceTransform); + + changeTracker.MarkInstancerClean(id); +} + +VtMatrix4dArray HdArnoldInstancer::CalculateInstanceMatrices(const SdfPath& prototypeId) +{ + const auto& id = GetId(); + + const auto instanceIndices = GetDelegate()->GetInstanceIndices(id, prototypeId); + + if (instanceIndices.empty()) { + return {}; + } + + _SyncPrimvars(); + + const auto numInstances = instanceIndices.size(); +#ifdef USD_HAS_NEW_INSTANCER_TRANSFORM + const auto instancerTransform = GetDelegate()->GetInstancerTransform(id); +#else + const auto instancerTransform = GetDelegate()->GetTransform(id); +#endif + + VtMatrix4dArray transforms(numInstances, instancerTransform); + + if (!_translate.empty()) { + GfMatrix4d translateMatrix(1.0); + for (auto i = decltype(numInstances){0}; i < numInstances; ++i) { + translateMatrix.SetTranslate(_translate[instanceIndices[i]]); + transforms[i] = translateMatrix * transforms[i]; + } + } + + if (!_rotate.empty()) { + GfMatrix4d rotateMatrix(1.0); + for (auto i = decltype(numInstances){0}; i < numInstances; ++i) { + const auto quat = _rotate[instanceIndices[i]]; + rotateMatrix.SetRotate(GfRotation(GfQuaternion(quat[0], GfVec3f(quat[1], quat[2], quat[3])))); + transforms[i] = rotateMatrix * transforms[i]; + } + } + + if (!_scale.empty()) { + GfMatrix4d scaleMatrix(1.0); + for (auto i = decltype(numInstances){0}; i < numInstances; ++i) { + scaleMatrix.SetScale(_scale[instanceIndices[i]]); + transforms[i] = scaleMatrix * transforms[i]; + } + } + + if (!_instanceTransform.empty()) { + for (auto i = decltype(numInstances){0}; i < numInstances; ++i) { + transforms[i] = _instanceTransform[instanceIndices[i]] * transforms[i]; + } + } + + // TODO(pal): support motion blur. + + if (GetParentId().IsEmpty()) { + return transforms; + } + + auto* parentInstancer = + static_cast(GetDelegate()->GetRenderIndex().GetInstancer(GetParentId())); + if (!TF_VERIFY(parentInstancer)) { + return transforms; + } + + const auto parentTransforms = parentInstancer->CalculateInstanceMatrices(id); + + const auto numParentInstances = parentTransforms.size(); + if (numParentInstances == 0) { + return transforms; + } + + if (numParentInstances > 1) { + transforms.resize(numInstances * numParentInstances); + } + + for (auto i = numParentInstances; i > 0; --i) { + const auto parentId = i - 1; + for (auto j = decltype(numInstances){0}; j < numInstances; ++j) { + transforms[j + parentId * numInstances] = transforms[j] * parentTransforms[parentId]; + } + } + + return transforms; +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/instancer.h b/render_delegate/instancer.h new file mode 100755 index 0000000000..9979b04294 --- /dev/null +++ b/render_delegate/instancer.h @@ -0,0 +1,76 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License.// Copyright (c) 2019 Autodesk, Inc., all rights reserved +/// @file instancer.h +/// +/// Utilities to support point instancers. +#pragma once + +#include "api.h" + +#include + +#include + +#include +#include +#include + +#include +#include + +#include "render_delegate.h" + +PXR_NAMESPACE_OPEN_SCOPE + +/// Utility class for the point instancer. +class HdArnoldInstancer : public HdInstancer { +public: + /// Creates an instance of HdArnoldInstancer. + /// + /// @param renderDelegate Pointer to the render delegate creating the + /// instancer. + HDARNOLD_API + HdArnoldInstancer( + HdArnoldRenderDelegate* renderDelegate, HdSceneDelegate* sceneDelegate, const SdfPath& id, + const SdfPath& parentInstancerId = SdfPath()); + + /// Destructor for HdArnoldInstancer. + ~HdArnoldInstancer() override = default; + + /// Calculates the matrices for all instances for a given shape. + /// + /// Values are cached and only updated when the primvars are dirtied. + /// + /// @param prototypeId ID of the instanced shape. + /// @return All the matrices for the shape. + HDARNOLD_API + VtMatrix4dArray CalculateInstanceMatrices(const SdfPath& prototypeId); + +protected: + /// Syncs the primvars for the instancer. + /// + /// Safe to call on multiple threads. + HDARNOLD_API + void _SyncPrimvars(); + + HdArnoldRenderDelegate* _delegate; ///< The active render delegate. + std::mutex _mutex; ///< Mutex to safe-guard calls to _SyncPrimvars. + + VtVec3fArray _translate; ///< Translation for each instance. + VtVec4fArray _rotate; ///< Rotation for each instance. + VtVec3fArray _scale; ///< Scale for each instance. + VtMatrix4dArray _instanceTransform; ///< Transforms for each instance. +}; + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/light.cpp b/render_delegate/light.cpp new file mode 100755 index 0000000000..75b9e98d3b --- /dev/null +++ b/render_delegate/light.cpp @@ -0,0 +1,370 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "light.h" + +#include + +#include + +#include + +#include "constant_strings.h" +#include "material.h" +#include "utils.h" + +PXR_NAMESPACE_OPEN_SCOPE + +namespace { + +struct ParamDesc { + ParamDesc(const char* aname, const TfToken& hname) : arnoldName(aname), hdName(hname) {} + AtString arnoldName; + TfToken hdName; +}; + +std::vector genericParams = { + {"intensity", HdLightTokens->intensity}, + {"exposure", HdLightTokens->exposure}, + {"color", HdLightTokens->color}, + {"diffuse", HdLightTokens->diffuse}, + {"specular", HdLightTokens->specular}, + {"normalize", HdLightTokens->normalize}, + {"cast_shadows", HdLightTokens->shadowEnable}, + {"shadow_color", HdLightTokens->shadowColor}, +}; + +std::vector pointParams = {{"radius", HdLightTokens->radius}}; + +std::vector distantParams = {{"angle", HdLightTokens->angle}}; + +std::vector diskParams = {{"radius", HdLightTokens->radius}}; + +std::vector cylinderParams = {{"radius", HdLightTokens->radius}}; + +void iterateParams( + AtNode* light, const AtNodeEntry* nentry, const SdfPath& id, HdSceneDelegate* delegate, + const std::vector& params) +{ + for (const auto& param : params) { + const auto* pentry = AiNodeEntryLookUpParameter(nentry, param.arnoldName); + if (pentry == nullptr) { + continue; + } + HdArnoldSetParameter(light, pentry, delegate->GetLightParamValue(id, param.hdName)); + } +} + +auto pointLightSync = [](AtNode* light, const AtNodeEntry* nentry, const SdfPath& id, HdSceneDelegate* delegate) { + iterateParams(light, nentry, id, delegate, pointParams); +}; + +auto distantLightSync = [](AtNode* light, const AtNodeEntry* nentry, const SdfPath& id, HdSceneDelegate* delegate) { + iterateParams(light, nentry, id, delegate, distantParams); +}; + +auto diskLightSync = [](AtNode* light, const AtNodeEntry* nentry, const SdfPath& id, HdSceneDelegate* delegate) { + iterateParams(light, nentry, id, delegate, diskParams); +}; + +auto rectLightSync = [](AtNode* light, const AtNodeEntry* nentry, const SdfPath& id, HdSceneDelegate* delegate) { + float width = 1.0f; + float height = 1.0f; + const auto& widthValue = delegate->GetLightParamValue(id, HdLightTokens->width); + if (widthValue.IsHolding()) { + width = widthValue.UncheckedGet(); + } + const auto& heightValue = delegate->GetLightParamValue(id, HdLightTokens->height); + if (heightValue.IsHolding()) { + height = heightValue.UncheckedGet(); + } + + width /= 2.0f; + height /= 2.0f; + + AiNodeSetArray( + light, "vertices", + AiArray( + 4, 1, AI_TYPE_VECTOR, AtVector(-width, height, 0.0f), AtVector(width, height, 0.0f), + AtVector(width, -height, 0.0f), AtVector(-width, -height, 0.0f))); +}; + +auto cylinderLightSync = [](AtNode* light, const AtNodeEntry* nentry, const SdfPath& id, HdSceneDelegate* delegate) { + iterateParams(light, nentry, id, delegate, cylinderParams); + float length = 1.0f; + const auto& lengthValue = delegate->GetLightParamValue(id, UsdLuxTokens->length); + if (lengthValue.IsHolding()) { + length = lengthValue.UncheckedGet(); + } + length /= 2.0f; + AiNodeSetVec(light, "bottom", 0.0f, -length, 0.0f); + AiNodeSetVec(light, "top", 0.0f, length, 0.0f); +}; + +auto domeLightSync = [](AtNode* light, const AtNodeEntry* nentry, const SdfPath& id, HdSceneDelegate* delegate) { + const auto& formatValue = delegate->GetLightParamValue(id, UsdLuxTokens->textureFormat); + if (formatValue.IsHolding()) { + const auto& textureFormat = formatValue.UncheckedGet(); + if (textureFormat == UsdLuxTokens->latlong) { + AiNodeSetStr(light, str::format, str::latlong); + } else if (textureFormat == UsdLuxTokens->mirroredBall) { + AiNodeSetStr(light, str::format, str::mirrored_ball); + } else { + AiNodeSetStr(light, str::format, str::angular); // default value + } + } +}; + +/// Utility class to translate Hydra lights for th Render Delegate. +class HdArnoldGenericLight : public HdLight { +public: + using SyncParams = void (*)(AtNode*, const AtNodeEntry*, const SdfPath&, HdSceneDelegate*); + + /// Internal constructor for creating HdArnoldGenericLight. + /// + /// @param delegate Pointer to the Render Delegate. + /// @param id Path to the Hydra Primitive. + /// @param arnoldType The type of the Arnold light. + /// @param sync Function object syncing light specific parameters between + /// the Hydra Primitive and the Arnold Light. + /// @param supportsTexture Value to indicate if the light supports textures. + HdArnoldGenericLight( + HdArnoldRenderDelegate* delegate, const SdfPath& id, const AtString& arnoldType, const SyncParams& sync, + bool supportsTexture = false); + + /// Destructor for the Arnold Light. + /// + /// Destroys Arnold Light and any shaders created. + ~HdArnoldGenericLight() override; + + /// Syncing parameters from the Hydra primitive to the Arnold light. + /// + /// @param sceneDelegate Pointer to the Scene Delegate. + /// @param renderParam Pointer to HdArnoldRenderParam. + /// @param dirtyBits Dirty Bits of the Hydra primitive. + void Sync(HdSceneDelegate* sceneDelegate, HdRenderParam* renderParam, HdDirtyBits* dirtyBits) override; + + /// Returns the set of initial dirty bits. + /// + /// @return Value of the initial dirty bits. + HdDirtyBits GetInitialDirtyBitsMask() const override; + + /// Sets up the texture for the Arnold Light. + /// + /// @param value Value holding an SdfAssetPath to the texture. + void SetupTexture(const VtValue& value); + +private: + SyncParams _syncParams; ///< Function object to sync light parameters. + HdArnoldRenderDelegate* _delegate; ///< Pointer to the Render Delegate. + AtNode* _light; ///< Pointer to the Arnold Light. + AtNode* _texture = nullptr; ///< Pointer to the Arnold Texture Shader. + bool _supportsTexture = false; ///< Value indicating texture support. +}; + +HdArnoldGenericLight::HdArnoldGenericLight( + HdArnoldRenderDelegate* delegate, const SdfPath& id, const AtString& arnoldType, + const HdArnoldGenericLight::SyncParams& sync, bool supportsTexture) + : HdLight(id), _syncParams(sync), _delegate(delegate), _supportsTexture(supportsTexture) +{ + _light = AiNode(_delegate->GetUniverse(), arnoldType); + if (id.IsEmpty()) { + AiNodeSetFlt(_light, "intensity", 0.0f); + } else { + AiNodeSetStr(_light, "name", id.GetText()); + } +} + +HdArnoldGenericLight::~HdArnoldGenericLight() +{ + AiNodeDestroy(_light); + if (_texture != nullptr) { + AiNodeDestroy(_texture); + } +} + +void HdArnoldGenericLight::Sync(HdSceneDelegate* sceneDelegate, HdRenderParam* renderParam, HdDirtyBits* dirtyBits) +{ + auto* param = reinterpret_cast(renderParam); + TF_UNUSED(sceneDelegate); + TF_UNUSED(dirtyBits); + if (*dirtyBits & HdLight::DirtyParams) { + param->End(); + const auto id = GetId(); + const auto* nentry = AiNodeGetNodeEntry(_light); + AiNodeReset(_light); + iterateParams(_light, nentry, id, sceneDelegate, genericParams); + _syncParams(_light, nentry, id, sceneDelegate); + if (_supportsTexture) { + SetupTexture(sceneDelegate->GetLightParamValue(id, HdLightTokens->textureFile)); + } + for (const auto& primvar : sceneDelegate->GetPrimvarDescriptors(id, HdInterpolation::HdInterpolationConstant)) { + ConvertPrimvarToBuiltinParameter(_light, id, sceneDelegate, primvar); + } + } + + if (*dirtyBits & HdLight::DirtyTransform) { + param->End(); + HdArnoldSetTransform(_light, sceneDelegate, GetId()); + } + + *dirtyBits = HdLight::Clean; +} + +void HdArnoldGenericLight::SetupTexture(const VtValue& value) +{ + const auto* nentry = AiNodeGetNodeEntry(_light); + const auto hasShader = AiNodeEntryLookUpParameter(nentry, str::shader) != nullptr; + if (hasShader) { + AiNodeSetPtr(_light, str::shader, nullptr); + } else { + AiNodeUnlink(_light, str::color); + } + if (_texture != nullptr) { + AiNodeDestroy(_texture); + _texture = nullptr; + } + if (!value.IsHolding()) { + return; + } + const auto& assetPath = value.UncheckedGet(); + auto path = assetPath.GetResolvedPath(); + if (path.empty()) { + path = assetPath.GetAssetPath(); + } + + if (path.empty()) { + return; + } + _texture = AiNode(_delegate->GetUniverse(), str::image); + AiNodeSetStr(_texture, str::filename, path.c_str()); + if (hasShader) { + AiNodeSetPtr(_light, str::shader, _texture); + } else { // Connect to color if filename doesn't exists. + AiNodeLink(_texture, str::color, _light); + } +} + +HdDirtyBits HdArnoldGenericLight::GetInitialDirtyBitsMask() const +{ + return HdLight::DirtyParams | HdLight::DirtyTransform; +} + +class HdArnoldSimpleLight : public HdLight { +public: + /// Internal constructor for creating HdArnoldSimpleLight. + /// + /// @param delegate Pointer to the Render Delegate. + /// @param id Path to the Hydra Primitive. + HdArnoldSimpleLight(HdArnoldRenderDelegate* delegate, const SdfPath& id); + + /// Destructor for the Arnold Light. + /// + /// Destroys Arnold Light created. + ~HdArnoldSimpleLight() override; + + /// Syncing parameters from the Hydra primitive to the Arnold light. + /// + /// Contrary to the HdArnoldGeneric light, the arnold node is only created + /// in the sync function. + /// + /// @param sceneDelegate Pointer to the Scene Delegate. + /// @param renderParam Pointer to HdArnoldRenderParam. + /// @param dirtyBits Dirty Bits of the Hydra primitive. + void Sync(HdSceneDelegate* sceneDelegate, HdRenderParam* renderParam, HdDirtyBits* dirtyBits) override; + + /// Returns the set of initial dirty bits. + /// + /// @return Value of the initial dirty bits. + HdDirtyBits GetInitialDirtyBitsMask() const override; + +private: + HdArnoldRenderDelegate* _delegate; ///< Pointer to the Render Delegate. + AtNode* _light; ///< Pointer to the Arnold Light. +}; + +HdArnoldSimpleLight::HdArnoldSimpleLight(HdArnoldRenderDelegate* delegate, const SdfPath& id) : HdLight(id) {} + +HdArnoldSimpleLight::~HdArnoldSimpleLight() +{ + if (_light != nullptr) { + AiNodeDestroy(_light); + } +} + +void HdArnoldSimpleLight::Sync(HdSceneDelegate* sceneDelegate, HdRenderParam* renderParam, HdDirtyBits* dirtyBits) +{ + *dirtyBits = HdLight::Clean; +} + +HdDirtyBits HdArnoldSimpleLight::GetInitialDirtyBitsMask() const +{ + return HdLight::DirtyTransform | HdLight::DirtyParams; +} + +} // namespace + +namespace HdArnoldLight { + +HdLight* CreatePointLight(HdArnoldRenderDelegate* delegate, const SdfPath& id) +{ + return new HdArnoldGenericLight(delegate, id, str::point_light, pointLightSync); +} + +HdLight* CreateDistantLight(HdArnoldRenderDelegate* delegate, const SdfPath& id) +{ + return new HdArnoldGenericLight(delegate, id, str::distant_light, distantLightSync); +} + +HdLight* CreateDiskLight(HdArnoldRenderDelegate* delegate, const SdfPath& id) +{ + return new HdArnoldGenericLight(delegate, id, str::disk_light, diskLightSync); +} + +HdLight* CreateRectLight(HdArnoldRenderDelegate* delegate, const SdfPath& id) +{ + return new HdArnoldGenericLight(delegate, id, str::quad_light, rectLightSync, true); +} + +HdLight* CreateCylinderLight(HdArnoldRenderDelegate* delegate, const SdfPath& id) +{ + return new HdArnoldGenericLight(delegate, id, str::cylinder_light, cylinderLightSync); +} + +HdLight* CreateDomeLight(HdArnoldRenderDelegate* delegate, const SdfPath& id) +{ + return new HdArnoldGenericLight(delegate, id, str::skydome_light, domeLightSync, true); +} + +HdLight* CreateSimpleLight(HdArnoldRenderDelegate* delegate, const SdfPath& id) +{ + return new HdArnoldSimpleLight(delegate, id); +} + +} // namespace HdArnoldLight + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/light.h b/render_delegate/light.h new file mode 100755 index 0000000000..74005af73e --- /dev/null +++ b/render_delegate/light.h @@ -0,0 +1,104 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/// @file light.h +/// +/// Utilities to translating Hydra lights for the Render Delegate. +#pragma once +#include +#include "api.h" + +#include + +#include "hdarnold.h" +#include "render_delegate.h" + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +namespace HdArnoldLight { + +/// Returns an instance of HdArnoldLight for handling point lights. +/// +/// @param delegate Pointer to the Render Delegate. +/// @param id Path to the Hydra Primitive. +/// @return Instance of HdArnoldLight. +HDARNOLD_API +HdLight* CreatePointLight(HdArnoldRenderDelegate* delegate, const SdfPath& id); + +/// Returns an instance of HdArnoldLight for handling distant lights. +/// +/// @param delegate Pointer to the Render Delegate. +/// @param id Path to the Hydra Primitive. +/// @return Instance of HdArnoldLight. +HDARNOLD_API +HdLight* CreateDistantLight(HdArnoldRenderDelegate* delegate, const SdfPath& id); + +/// Returns an instance of HdArnoldLight for handling disk lights. +/// +/// @param delegate Pointer to the Render Delegate. +/// @param id Path to the Hydra Primitive. +/// @return Instance of HdArnoldLight. +HDARNOLD_API +HdLight* CreateDiskLight(HdArnoldRenderDelegate* delegate, const SdfPath& id); + +/// Returns an instance of HdArnoldLight for handling rect lights. +/// +/// @param delegate Pointer to the Render Delegate. +/// @param id Path to the Hydra Primitive. +/// @return Instance of HdArnoldLight. +HDARNOLD_API +HdLight* CreateRectLight(HdArnoldRenderDelegate* delegate, const SdfPath& id); + +/// Returns an instance of HdArnoldLight for handling cylinder lights. +/// +/// @param delegate Pointer to the Render Delegate. +/// @param id Path to the Hydra Primitive. +/// @return Instance of HdArnoldLight. +HDARNOLD_API +HdLight* CreateCylinderLight(HdArnoldRenderDelegate* delegate, const SdfPath& id); + +/// Returns an instance of HdArnoldLight for handling dome lights. +/// +/// @param delegate Pointer to the Render Delegate. +/// @param id Path to the Hydra Primitive. +/// @return Instance of HdArnoldLight. +HDARNOLD_API +HdLight* CreateDomeLight(HdArnoldRenderDelegate* delegate, const SdfPath& id); + +/// Returns an instance of HdArnoldLight for handling simple lights. +/// +/// @param delegate Pointer to the Render Delegate. +/// @param id Path to the Hydra Primitive. +/// @return Instance of HdArnoldLight. +HDARNOLD_API +HdLight* CreateSimpleLight(HdArnoldRenderDelegate* delegate, const SdfPath& id); + +} // namespace HdArnoldLight + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/material.cpp b/render_delegate/material.cpp new file mode 100755 index 0000000000..f8b6a8907e --- /dev/null +++ b/render_delegate/material.cpp @@ -0,0 +1,637 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "material.h" + +#include + +#include "constant_strings.h" +#include "debug_codes.h" +#include "hdarnold.h" +#include "utils.h" + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +// clang-format off +TF_DEFINE_PRIVATE_TOKENS(_tokens, + (x) + (y) + (z) + (r) + (g) + (b) + (a) + (standard) + (file) + (katanaColor) + (flipT) + (diffuseTexture) +); +// clang-format on + +namespace { + +class MaterialEditContext { +public: + MaterialEditContext() = default; + + virtual ~MaterialEditContext() = default; + + MaterialEditContext(const MaterialEditContext&) = delete; + + MaterialEditContext(MaterialEditContext&&) = delete; + + MaterialEditContext& operator=(const MaterialEditContext&) = delete; + + MaterialEditContext& operator=(MaterialEditContext&&) = delete; + + /// Access the value of any parameter on the material. + /// + /// This helps the remap function to make decisions about output type or + /// default values based on existing parameters. + /// + /// @param paramName Name of the param. + /// @return Value of the param wrapped in VtValue. + virtual VtValue GetParam(const TfToken& paramName) = 0; + + /// Change the value of any parameter on the material. + /// + /// This is useful to set default values for parameters before remapping + /// from existing USD parameters. + /// + /// @param paramName Name of the parameter to set. + /// @param paramValue New value of the parameter wrapped in VtValue. + virtual void SetParam(const TfToken& paramName, const VtValue& paramValue) = 0; + + /// Change the id of the material. + /// + /// This can be used to change the type of the node, ie, change + /// PxrPreviewSurface to standard_surface as part of the conversion. + virtual void SetNodeId(const TfToken& nodeId) = 0; + + /// RenameParam's function is to remap a parameter from the USD/HYdra name + /// to the arnold name and remap connections. + /// + /// @param oldParamName The original, USD/Hydra parameter name. + /// @param newParamName The new, Arnold parameter name. + virtual void RenameParam(const TfToken& oldParamName, const TfToken& newParamName) = 0; +}; + +class HydraMaterialEditContext : public MaterialEditContext { +public: + HydraMaterialEditContext(HdMaterialNetwork& network, HdMaterialNode& node) : _network(network), _node(node) {} + + VtValue GetParam(const TfToken& paramName) override + { + const auto paramIt = _node.parameters.find(paramName); + return paramIt == _node.parameters.end() ? VtValue() : paramIt->second; + } + + void SetParam(const TfToken& paramName, const VtValue& paramValue) override + { + _node.parameters[paramName] = paramValue; + } + + void SetNodeId(const TfToken& nodeId) override { _node.identifier = nodeId; } + + void RenameParam(const TfToken& oldParamName, const TfToken& newParamName) override + { + const auto oldValue = GetParam(oldParamName); + if (!oldValue.IsEmpty()) { + _node.parameters.erase(oldParamName); + _node.parameters[newParamName] = oldValue; + } + + for (auto& relationship : _network.relationships) { + if (relationship.outputId == _node.path && relationship.outputName == oldParamName) { + relationship.outputName = newParamName; + } + } + } + +private: + HdMaterialNetwork& _network; + HdMaterialNode& _node; +}; + +using RemapNodeFunc = void (*)(MaterialEditContext*); + +RemapNodeFunc _previewSurfaceRemapFunc = [](MaterialEditContext* ctx) { + ctx->SetNodeId(str::t_standard_surface); + // Defaults that are different from the PreviewSurface. We are setting these + // before renaming the parameter, so they'll be overwritten with existing values. + ctx->SetParam(str::t_base_color, VtValue(GfVec3f(0.18f, 0.18f, 0.18f))); + ctx->SetParam(str::t_base, VtValue(1.0f)); + ctx->SetParam(str::t_emission, VtValue(1.0f)); + ctx->SetParam(str::t_emission_color, VtValue(GfVec3f(0.0f, 0.0f, 0.0f))); + ctx->SetParam(str::t_specular_color, VtValue(GfVec3f(1.0f, 1.0f, 1.0f))); + ctx->SetParam(str::t_specular_roughness, VtValue(0.5f)); + ctx->SetParam(str::t_specular_IOR, VtValue(1.5f)); + ctx->SetParam(str::t_coat, VtValue(0.0f)); + ctx->SetParam(str::t_coat_roughness, VtValue(0.01f)); + + const auto useSpecularWorkflow = ctx->GetParam(str::t_useSpecularWorkflow); + // Default value is 0. + if (useSpecularWorkflow.IsHolding() && useSpecularWorkflow.UncheckedGet() == 1) { + ctx->RenameParam(str::t_specularColor, str::t_specular_color); + } else { + ctx->RenameParam(str::t_metalness, str::t_metallic); + } + + // Float opacity needs to be remapped to color. + const auto opacityValue = ctx->GetParam(str::t_opacity); + if (opacityValue.IsHolding()) { + const auto opacity = opacityValue.UncheckedGet(); + ctx->SetParam(str::t_opacity, VtValue(GfVec3f(opacity, opacity, opacity))); + } + + ctx->RenameParam(str::t_diffuseColor, str::t_base_color); + ctx->RenameParam(str::t_emissiveColor, str::t_emission_color); + ctx->RenameParam(str::t_roughness, str::t_specular_roughness); + ctx->RenameParam(str::t_ior, str::t_specular_IOR); + ctx->RenameParam(str::t_clearcoat, str::t_coat); + ctx->RenameParam(str::t_clearcoatRoughness, str::t_coat_roughness); + // We rename the normal to something that doesn't exist for now, because + // to handle it correctly we would need to make a normal_map node, and + // hook things up... but this framework doesn't allow for creation of other + // nodes yet. + ctx->RenameParam(str::t_normal, str::t_normal_nonexistant_rename); +}; + +RemapNodeFunc _uvTextureRemapFunc = [](MaterialEditContext* ctx) { + ctx->SetNodeId(str::t_image); + ctx->RenameParam(str::t_file, str::t_filename); + ctx->RenameParam(str::t_st, str::t_uvcoords); + ctx->RenameParam(str::t_fallback, str::t_missing_texture_color); +}; + +RemapNodeFunc _floatPrimvarRemapFunc = [](MaterialEditContext* ctx) { + ctx->SetNodeId(str::t_user_data_float); + ctx->RenameParam(str::t_varname, str::t_attribute); + ctx->RenameParam(str::t_fallback, str::t_defaultStr); +}; + +// Since st and uv is set as the built-in UV parameter on the mesh, we +// have to use a utility node instead of a user_data_rgb node. +RemapNodeFunc _float2PrimvarRemapFunc = [](MaterialEditContext* ctx) { + const auto varnameValue = ctx->GetParam(str::t_varname); + if (varnameValue.IsEmpty() || !varnameValue.IsHolding()) { + return; + } + const auto& varname = varnameValue.UncheckedGet(); + // uv and st is remapped to UV coordinates + if (varname == str::t_uv || varname == str::t_st) { + // We are reading the uv from the mesh. + ctx->SetNodeId(str::t_utility); + ctx->SetParam(str::t_color_mode, VtValue(str::t_uv)); + ctx->SetParam(str::t_shade_mode, VtValue(str::t_flat)); + } else { + ctx->SetNodeId(str::t_user_data_rgb); + ctx->RenameParam(str::t_varname, str::t_attribute); + } + ctx->RenameParam(str::t_fallback, str::t_defaultStr); +}; + +RemapNodeFunc _float3PrimvarRemapFunc = [](MaterialEditContext* ctx) { + ctx->SetNodeId(str::t_user_data_rgb); + ctx->RenameParam(str::t_varname, str::t_attribute); + ctx->RenameParam(str::t_fallback, str::t_defaultStr); +}; + +RemapNodeFunc _float4PrimvarRemapFunc = [](MaterialEditContext* ctx) { + ctx->SetNodeId(str::t_user_data_rgba); + ctx->RenameParam(str::t_varname, str::t_attribute); + ctx->RenameParam(str::t_fallback, str::t_defaultStr); +}; + +RemapNodeFunc _intPrimvarRemapFunc = [](MaterialEditContext* ctx) { + ctx->SetNodeId(str::t_user_data_int); + ctx->RenameParam(str::t_varname, str::t_attribute); + ctx->RenameParam(str::t_fallback, str::t_defaultStr); +}; + +RemapNodeFunc _stringPrimvarRemapFunc = [](MaterialEditContext* ctx) { + ctx->SetNodeId(str::t_user_data_string); + ctx->RenameParam(str::t_varname, str::t_attribute); + ctx->RenameParam(str::t_fallback, str::t_defaultStr); +}; + +const std::unordered_map _nodeRemapFuncs{ + {str::t_UsdPreviewSurface, _previewSurfaceRemapFunc}, + {str::t_UsdUVTexture, _uvTextureRemapFunc}, + {str::t_UsdPrimvarReader_float, _floatPrimvarRemapFunc}, + {str::t_UsdPrimvarReader_float2, _float2PrimvarRemapFunc}, + {str::t_UsdPrimvarReader_float3, _float3PrimvarRemapFunc}, + {str::t_UsdPrimvarReader_point, _float3PrimvarRemapFunc}, + {str::t_UsdPrimvarReader_normal, _float3PrimvarRemapFunc}, + {str::t_UsdPrimvarReader_vector, _float3PrimvarRemapFunc}, + {str::t_UsdPrimvarReader_float4, _float4PrimvarRemapFunc}, + {str::t_UsdPrimvarReader_int, _intPrimvarRemapFunc}, + {str::t_UsdPrimvarReader_string, _stringPrimvarRemapFunc}, +}; + +void _RemapNetwork(HdMaterialNetwork& network) +{ + auto isUVTexture = [&](const SdfPath& id) -> bool { + for (const auto& material : network.nodes) { + if (material.path == id && material.identifier == str::t_UsdUVTexture) { + return true; + } + } + return false; + }; + + auto isSTFloat2PrimvarReader = [&](const SdfPath& id) -> bool { + for (const auto& material : network.nodes) { + if (material.path == id && material.identifier == str::t_UsdPrimvarReader_float2) { + const auto paramIt = material.parameters.find(str::t_varname); + if (paramIt == material.parameters.end() || !paramIt->second.IsHolding()) { + return true; + } + const auto& token = paramIt->second.UncheckedGet(); + return token == str::t_uv || token == str::t_st; + } + } + return false; + }; + // We are invalidating any float 2 primvar reader connection with either uv + // or st primvar to a usd uv texture. + for (auto& relationship : network.relationships) { + if (relationship.outputName == str::t_st) { + // We check if the node is a UsdUVTexture + if (isUVTexture(relationship.outputId) && isSTFloat2PrimvarReader(relationship.inputId)) { + // We need to keep the inputId, otherwise we won't be able to find + // the entry point to the shader network. + relationship.outputId = SdfPath(); + } + } + } + + for (auto& material : network.nodes) { + const auto remapIt = _nodeRemapFuncs.find(material.identifier); + if (remapIt == _nodeRemapFuncs.end()) { + continue; + } + + HydraMaterialEditContext editCtx(network, material); + remapIt->second(&editCtx); + } +} + +enum class KatanaShader { katana_constant, katana_default, katana_surface, invalid }; + +KatanaShader _GetKatanaShaderType(const std::string& code) +{ + constexpr auto katanaConstantName = "katana_constant.glslfx"; + constexpr auto katanaDefaultName = "katana_default.glslfx"; + constexpr auto katanaSurfaceName = "katana_surface.glslfx"; + if (code.find(katanaConstantName) != std::string::npos) { + return KatanaShader::katana_constant; + } else if (code.find(katanaDefaultName) != std::string::npos) { + return KatanaShader::katana_default; + } else if (code.find(katanaSurfaceName) != std::string::npos) { + return KatanaShader::katana_surface; + } else { + return KatanaShader::invalid; + } +} + +} // namespace + +HdArnoldMaterial::HdArnoldMaterial(HdArnoldRenderDelegate* delegate, const SdfPath& id) + : HdMaterial(id), _delegate(delegate) +{ + _surface = _delegate->GetFallbackShader(); + _volume = _delegate->GetFallbackVolumeShader(); +} + +HdArnoldMaterial::~HdArnoldMaterial() +{ + for (auto& node : _nodes) { + AiNodeDestroy(node.second.node); + } +} + +void HdArnoldMaterial::Sync(HdSceneDelegate* sceneDelegate, HdRenderParam* renderParam, HdDirtyBits* dirtyBits) +{ + auto* param = reinterpret_cast(renderParam); + const auto id = GetId(); + // Note, Katana 3.2 always dirties the resource, so we don't have to check + // for dirtyParams or dirtySurfaceShader. + if ((*dirtyBits & HdMaterial::DirtyResource) && !id.IsEmpty()) { + param->End(); + auto value = sceneDelegate->GetMaterialResource(GetId()); + AtNode* surfaceEntry = nullptr; + AtNode* displacementEntry = nullptr; + AtNode* volumeEntry = nullptr; + if (value.IsHolding()) { + const auto& map = value.UncheckedGet(); +#ifdef USD_HAS_NEW_MATERIAL_TERMINAL_TOKENS + const auto* surfaceNetwork = TfMapLookupPtr(map.map, HdMaterialTerminalTokens->surface); + const auto* displacementNetwork = TfMapLookupPtr(map.map, HdMaterialTerminalTokens->displacement); + const auto* volumeNetwork = TfMapLookupPtr(map.map, HdMaterialTerminalTokens->volume); +#else + const auto* surfaceNetwork = TfMapLookupPtr(map.map, UsdImagingTokens->bxdf); + const auto* displacementNetwork = nullptr; + const auto* volumeNetwork = nullptr; +#endif // USD_HAS_NEW_MATERIAL_TERMINAL_TOKENS + SetNodesUnused(); + auto readNetwork = [&](const HdMaterialNetwork* network) -> AtNode* { + if (network == nullptr) { + return nullptr; + } + // We are remapping the preview surface nodes to ones that are supported + // in Arnold. This way we can keep the export code untouched, + // and handle connection / node exports separately. + auto remappedNetwork = *network; + _RemapNetwork(remappedNetwork); + return ReadMaterialNetwork(remappedNetwork); + }; + surfaceEntry = readNetwork(surfaceNetwork); + displacementEntry = readNetwork(displacementNetwork); + volumeEntry = readNetwork(volumeNetwork); + ClearUnusedNodes(surfaceEntry, displacementEntry, volumeEntry); + } else { + // Katana 3.2 does not return a HdMaterialNetworkMap for now, but + // the shader source code. We grab the code and identify which material + // they use and translate it to standard_surface. + surfaceEntry = ReadKatana32Material(sceneDelegate, id); + } + _surface = surfaceEntry == nullptr ? _delegate->GetFallbackShader() : surfaceEntry; + _displacement = displacementEntry; + _volume = volumeEntry == nullptr ? _delegate->GetFallbackVolumeShader() : volumeEntry; + } + *dirtyBits = HdMaterial::Clean; +} + +HdDirtyBits HdArnoldMaterial::GetInitialDirtyBitsMask() const { return HdMaterial::DirtyResource; } + +void HdArnoldMaterial::Reload() {} + +AtNode* HdArnoldMaterial::GetSurfaceShader() const { return _surface; } + +AtNode* HdArnoldMaterial::GetDisplacementShader() const { return _displacement; } + +AtNode* HdArnoldMaterial::GetVolumeShader() const { return _volume; } + +AtNode* HdArnoldMaterial::ReadMaterialNetwork(const HdMaterialNetwork& network) +{ + std::vector nodes; + nodes.reserve(network.nodes.size()); + for (const auto& node : network.nodes) { + auto* n = ReadMaterial(node); + if (n != nullptr) { + nodes.push_back(n); + } + } + + // We have to return the entry point from this function, and there are + // no hard guarantees that the last node (or the first) is going to be the + // entry point to the network, so we look for the first node that's not the + // source to any of the connections. + for (const auto& relationship : network.relationships) { + auto* inputNode = FindMaterial(relationship.inputId); + if (inputNode == nullptr) { + continue; + } + nodes.erase(std::remove(nodes.begin(), nodes.end(), inputNode), nodes.end()); + auto* outputNode = FindMaterial(relationship.outputId); + if (outputNode == nullptr) { + continue; + } + const auto* outputNodeEntry = AiNodeGetNodeEntry(outputNode); + if (AiNodeEntryLookUpParameter(outputNodeEntry, relationship.outputName.GetText()) == nullptr) { + continue; + } + + // Arnold nodes can only have one output... but you can connect to sub components of them. + // USD doesn't yet have component connections / swizzling, but it's nodes can have multiple + // outputs to which you can connect. + // Sometimes, the output parameter name effectively acts like a channel connection (ie, + // UsdUVTexture.outputs:r), so check for this. + bool useInputName = false; + if (relationship.inputName.size() == 1) { + const auto* inputNodeEntry = AiNodeGetNodeEntry(inputNode); + auto inputType = AiNodeEntryGetOutputType(inputNodeEntry); + if (relationship.inputName == _tokens->x || relationship.inputName == _tokens->y) { + useInputName = (inputType == AI_TYPE_VECTOR || inputType == AI_TYPE_VECTOR2); + } else if (relationship.inputName == _tokens->z) { + useInputName = (inputType == AI_TYPE_VECTOR); + } else if ( + relationship.inputName == _tokens->r || relationship.inputName == _tokens->g || + relationship.inputName == _tokens->b) { + useInputName = (inputType == AI_TYPE_RGB || inputType == AI_TYPE_RGBA); + } else if (relationship.inputName == _tokens->a) { + useInputName = (inputType == AI_TYPE_RGBA); + } + } + if (useInputName) { + AiNodeLinkOutput( + inputNode, relationship.inputName.GetText(), outputNode, relationship.outputName.GetText()); + } else { + AiNodeLink(inputNode, relationship.outputName.GetText(), outputNode); + } + } + + auto* entryPoint = nodes.empty() ? nullptr : nodes.front(); + return entryPoint; +} + +AtNode* HdArnoldMaterial::ReadMaterial(const HdMaterialNode& material) +{ + const auto* nodeTypeStr = material.identifier.GetText(); + const AtString nodeType(strncmp(nodeTypeStr, "arnold:", 7) == 0 ? nodeTypeStr + 7 : nodeTypeStr); + TF_DEBUG(HDARNOLD_MATERIAL) + .Msg("HdArnoldMaterial::ReadMaterial - node %s - type %s\n", material.path.GetText(), nodeType.c_str()); + auto* ret = GetLocalNode(material.path, nodeType); + if (Ai_unlikely(ret == nullptr)) { + return nullptr; + } + + const auto* nentry = AiNodeGetNodeEntry(ret); + for (const auto& param : material.parameters) { + const auto& paramName = param.first; + const auto* pentry = AiNodeEntryLookUpParameter(nentry, AtString(paramName.GetText())); + if (pentry == nullptr) { + continue; + } + HdArnoldSetParameter(ret, pentry, param.second); + } + return ret; +} + +AtNode* HdArnoldMaterial::ReadKatana32Material(HdSceneDelegate* sceneDelegate, const SdfPath& id) +{ + for (auto& it : _nodes) { + it.second.updated = false; + } + + const auto surfaceCode = sceneDelegate->GetSurfaceShaderSource(id); + // We are looking for the surface shader's filename, found in + // /plugins/Resources/Core/Shaders/Surface. + // Either katana_constant.glslfx, katana_default.glslfx or + // katana_surface.glslfx. + // katana_constant -> constant surface color, emulating it via emission color. + // katana_default -> default material, with 0.7 diffuse. It also has a + // 0.1 ambient component but ignoring that. + // katana_surface -> default material with a texture connected to the diffuse + // color slot, specular and a parameter to flip v coordinates. Emulating it + // with a default standard_surface and optionally a connected texture. + const auto shaderType = _GetKatanaShaderType(surfaceCode); + if (shaderType == KatanaShader::invalid) { + TF_DEBUG(HDARNOLD_MATERIAL).Msg("\n\tUnsupported shader code received:\n\t%s", surfaceCode.c_str()); + ClearUnusedNodes(); + return nullptr; + } + static const SdfPath standardPath("/standard_surface"); + auto* entryPoint = GetLocalNode(standardPath, str::standard_surface); + if (shaderType == KatanaShader::katana_constant) { + TF_DEBUG(HDARNOLD_MATERIAL).Msg("\n\tConverting katana_constant to standard surface."); + AiNodeSetFlt(entryPoint, str::base, 0.0f); + AiNodeSetFlt(entryPoint, str::specular, 0.0f); + AiNodeSetFlt(entryPoint, str::emission, 1.0f); + const auto katanaColorValue = sceneDelegate->GetMaterialParamValue(id, _tokens->katanaColor); + if (katanaColorValue.IsHolding()) { + const auto& katanaColor = katanaColorValue.UncheckedGet(); + AiNodeSetRGB(entryPoint, str::emission_color, katanaColor[0], katanaColor[1], katanaColor[2]); + } + } else if (shaderType == KatanaShader::katana_default) { + TF_DEBUG(HDARNOLD_MATERIAL).Msg("\n\tConverting katana_default to standard surface."); + AiNodeSetFlt(entryPoint, str::base, 0.7f); + AiNodeSetFlt(entryPoint, str::specular, 0.0f); + } else { + static const SdfPath imagePath("/image"); + TF_DEBUG(HDARNOLD_MATERIAL).Msg("\n\tConverting katana_surface to standard surface."); + AiNodeSetFlt(entryPoint, str::base, 1.0f); + AiNodeSetFlt(entryPoint, str::specular, 1.0f); + const auto diffuseTextureValue = sceneDelegate->GetMaterialParamValue(id, _tokens->diffuseTexture); + if (diffuseTextureValue.IsHolding()) { + const auto diffuseTexture = diffuseTextureValue.UncheckedGet(); + if (!diffuseTexture.empty()) { + auto* image = GetLocalNode(imagePath, str::image); + AiNodeSetStr(image, str::filename, diffuseTexture.c_str()); + const auto flipTValue = sceneDelegate->GetMaterialParamValue(id, _tokens->flipT); + if (flipTValue.IsHolding()) { + AiNodeSetBool(image, str::tflip, flipTValue.UncheckedGet() != 0); + } + AiNodeLink(image, str::base_color, entryPoint); + } + } + } + ClearUnusedNodes(entryPoint); + return entryPoint; +} + +AtNode* HdArnoldMaterial::FindMaterial(const SdfPath& path) const +{ + const auto nodeIt = _nodes.find(path); + return nodeIt == _nodes.end() ? nullptr : nodeIt->second.node; +} + +AtString HdArnoldMaterial::GetLocalNodeName(const SdfPath& path) const +{ + const auto* pp = path.GetText(); + if (pp == nullptr || pp[0] == '\0') { + return AtString(path.GetText()); + } + const auto p = GetId().AppendPath(SdfPath(TfToken(pp + 1))); + return AtString(p.GetText()); +} + +AtNode* HdArnoldMaterial::GetLocalNode(const SdfPath& path, const AtString& nodeType) +{ + const auto nodeIt = _nodes.find(path); + // If the node already exists, we are checking if the node type is the same + // as the requested node type. While this is not meaningful for applications + // like usdview, which rebuild their scene every in case of changes like this, + // this is still useful for more interactive applications which keep the + // render index around for longer times, like Maya to Hydra. + if (nodeIt != _nodes.end()) { + if (AiNodeEntryGetNameAtString(AiNodeGetNodeEntry(nodeIt->second.node)) != nodeType) { + TF_DEBUG(HDARNOLD_MATERIAL).Msg(" existing node found, but type mismatch - deleting old node\n"); + if (nodeIt->second.node != nullptr) { + AiNodeDestroy(nodeIt->second.node); + } + _nodes.erase(nodeIt); + } else { + TF_DEBUG(HDARNOLD_MATERIAL).Msg(" existing node found - using it\n"); + nodeIt->second.updated = true; + if (nodeIt->second.node != nullptr) { + AiNodeReset(nodeIt->second.node); + } + return nodeIt->second.node; + } + } + auto* ret = AiNode(_delegate->GetUniverse(), nodeType); + _nodes.emplace(path, MaterialData{ret, true}); + if (ret == nullptr) { + TF_DEBUG(HDARNOLD_MATERIAL).Msg(" unable to create node of type %s - aborting\n", nodeType.c_str()); + return nullptr; + } + const auto nodeName = GetLocalNodeName(path); + AiNodeSetStr(ret, str::name, nodeName); + return ret; +} + +bool HdArnoldMaterial::ClearUnusedNodes( + const AtNode* surfaceEntryPoint, const AtNode* displacementEntryPoint, const AtNode* volumeEntryPoint) +{ + // We are removing any shaders that has not been updated during material + // translation. + // We only have guarantees to erase elements during iteration since C++14. + std::vector nodesToRemove; + for (auto& it : _nodes) { + if (!it.second.updated) { + if (it.second.node != nullptr) { + if (it.second.node == surfaceEntryPoint || it.second.node == displacementEntryPoint || + it.second.node == volumeEntryPoint) { + TF_CODING_ERROR( + "[HdArnold] Entry point to the material network is not translated! %s", + AiNodeGetName(it.second.node)); + return false; + } + AiNodeDestroy(it.second.node); + } + nodesToRemove.push_back(it.first); + } + } + for (const auto& it : nodesToRemove) { + _nodes.erase(it); + } + return true; +} + +void HdArnoldMaterial::SetNodesUnused() +{ + for (auto& it : _nodes) { + it.second.updated = false; + } +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/material.h b/render_delegate/material.h new file mode 100755 index 0000000000..600fbf2b36 --- /dev/null +++ b/render_delegate/material.h @@ -0,0 +1,197 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/// @file material.h +/// +/// Utilities for translating Hydra Materials for the Render Delegate. +#pragma once + +#include +#include "api.h" + +#include + +#include "render_delegate.h" + +#include + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +/// Utility class for translating Hydra Materials to Arnold Materials. +class HdArnoldMaterial : public HdMaterial { +public: + /// Constructor for HdArnoldMaterial. + /// + /// @param delegate Pointer to the Render Delegate. + /// @param id Path to the material. + HDARNOLD_API + HdArnoldMaterial(HdArnoldRenderDelegate* delegate, const SdfPath& id); + + /// Destructor for HdArnoldMaterial. + /// + /// Destory all Arnold Shader Nodes created. + ~HdArnoldMaterial() override; + + /// Syncing the Hydra Material to the Arnold Shader Network. + /// + /// @param sceneDelegate Pointer to the Scene Delegate. + /// @param renderPaaram Pointer to a HdArnoldRenderParam instance. + /// @param dirtyBits Dirty Bits to sync. + HDARNOLD_API + void Sync(HdSceneDelegate* sceneDelegate, HdRenderParam* renderParam, HdDirtyBits* dirtyBits) override; + + /// Returns the initial Dirty Bits for the Primitive. + HDARNOLD_API + HdDirtyBits GetInitialDirtyBitsMask() const override; + + /// Reloads the shader. + /// + /// Currently does nothing. + HDARNOLD_API + void Reload() override; + + /// Returns the Entry Point to the Surface Shader Network. + /// + /// @return Pointer to the top Surface Shader. + HDARNOLD_API + AtNode* GetSurfaceShader() const; + + /// Returns the entry point to the Displacement Shader Network. + /// + /// @return Pointer to the top Displacement Shader. + HDARNOLD_API + AtNode* GetDisplacementShader() const; + + /// Returns the entry point to the Volume Shader Network. + /// + /// @return Pointer to the top Volume Shader. + HDARNOLD_API + AtNode* GetVolumeShader() const; + +protected: + /// Utility struct to store Translated Materials. + struct MaterialData { + /// Constructor for emplace functions. + MaterialData(AtNode* _node, bool _updated) : node(_node), updated(_updated) {} + /// Pointer to the Arnold Node. + AtNode* node = nullptr; + /// Boolean to store if the material has been updated or not. + bool updated = false; + }; + + /// Convert a Hydra Material Network to an Arnold Shader Network. + /// + /// The newly created Arnold Nodes are stored in the class instance. Every + /// previously created Arnold Node that's not touched is destroyed. + /// + /// @param network Const Reference to the Hydra Material Network. + /// @return Returns the Entry Point to the Arnold Shader Network. + HDARNOLD_API + AtNode* ReadMaterialNetwork(const HdMaterialNetwork& network); + + /// Converts a Hydra Material to an Arnold Shader. + /// + /// The Arnold Node is stored in the class instance. Subsequent calls of a + /// node with the same path do not translate nodes twice or create + /// additional Arnold Nodes. + /// + /// @param material Const Reference to the Hydra Material Node. + /// @return Pointer to the Arnold Node. + HDARNOLD_API + AtNode* ReadMaterial(const HdMaterialNode& material); + + /// Converts a Material definition from Katana 3.2 to an Arnold Shader. + /// + /// Katana 3.2 returns shaders in a special way, returning shader code, + /// rather than a HdMaterialNetwork, so we are remapping the shader code + /// to standard surface nodes. + /// + /// @param sceneDelegate Pointer to the HdSceneDelegate. + /// @param id SdfPath to the material. + /// @return Pointer to the Arnold Node or nullptr if conversion was + /// unsuccessful. + HDARNOLD_API + AtNode* ReadKatana32Material(HdSceneDelegate* sceneDelegate, const SdfPath& id); + + /// Looks up a Material in the internal Arnold Node storage. + /// + /// @param id Path to the Hydra Material Node. + /// @return Pointer to the Material Data representing the Hydra Material + /// Node if the Hydra Material Node was already translated, nullptr otherwise. + HDARNOLD_API + AtNode* FindMaterial(const SdfPath& id) const; + + /// Returns a local node name prefixed by the Material's path. + /// + /// @param path Path to be prefixed. + /// @return AtString that holds the path prefixed with the Material's path. + HDARNOLD_API + AtString GetLocalNodeName(const SdfPath& path) const; + + /// Returns a local node based on the path and the node type. + /// + /// Creates a new node if the node can't be found with the given name or + /// it's not the right type. Returns the existing node if type and name + /// matches, nullptr if there is an error. It marks the node updated upon + /// successful return value. Existing materials are reset upon return. + /// + /// @param path Path to the node. + /// @param nodeType Type of the node. + /// @return Pointer to the node, nullptr if there was an error. + HDARNOLD_API + AtNode* GetLocalNode(const SdfPath& path, const AtString& nodeType); + + /// Clears all nodes that are not updated during sync. + /// + /// Confirms if the entry point is valid and updated, otherwise it prints + /// a coding error. + /// + /// @param entryPoint Point to the entry to the shader network. + /// @return True if entry point was translated, false otherwise. + HDARNOLD_API + bool ClearUnusedNodes( + const AtNode* surfaceEntryPoint = nullptr, const AtNode* displacementEntryPoint = nullptr, + const AtNode* volumeEntryPoint = nullptr); + + /// Sets all shader nodes unused. + HDARNOLD_API + void SetNodesUnused(); + + /// Storage for nodes created by HdArnoldMaterial. + std::unordered_map _nodes; + HdArnoldRenderDelegate* _delegate; ///< Pointer to the Render Delegate. + /// Pointer to the entry point to the Surface Shader Network. + AtNode* _surface = nullptr; + /// Pointer to the entry point to the Displacement Shader Network. + AtNode* _displacement = nullptr; + /// Pointer to the entry point to the Volume Shader Network. + AtNode* _volume = nullptr; +}; + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/mesh.cpp b/render_delegate/mesh.cpp new file mode 100755 index 0000000000..ebed1b675f --- /dev/null +++ b/render_delegate/mesh.cpp @@ -0,0 +1,263 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "mesh.h" + +#include +#include + +#include + +#include "constant_strings.h" +#include "instancer.h" +#include "material.h" +#include "utils.h" + +PXR_NAMESPACE_OPEN_SCOPE + +// clang-format off +TF_DEFINE_PRIVATE_TOKENS(_tokens, + (st) + (uv) +); +// clang-format on + +HdArnoldMesh::HdArnoldMesh(HdArnoldRenderDelegate* delegate, const SdfPath& id, const SdfPath& instancerId) + : HdMesh(id, instancerId), _shape(str::polymesh, delegate, id, GetPrimId()) +{ + // The default value is 1, which won't work well in a Hydra context. + AiNodeSetByte(_shape.GetShape(), str::subdiv_iterations, 0); +} + +void HdArnoldMesh::Sync( + HdSceneDelegate* delegate, HdRenderParam* renderParam, HdDirtyBits* dirtyBits, const TfToken& reprToken) +{ + TF_UNUSED(reprToken); + auto* param = reinterpret_cast(renderParam); + const auto& id = GetId(); + + if (HdChangeTracker::IsPrimvarDirty(*dirtyBits, id, HdTokens->points)) { + param->End(); + HdArnoldSetPositionFromPrimvar(_shape.GetShape(), id, delegate, str::vlist); + } + + if (HdChangeTracker::IsTopologyDirty(*dirtyBits, id)) { + param->End(); + const auto topology = GetMeshTopology(delegate); + const auto& vertexCounts = topology.GetFaceVertexCounts(); + const auto& vertexIndices = topology.GetFaceVertexIndices(); + const auto numFaces = topology.GetNumFaces(); + const auto numVertexIndices = vertexIndices.size(); + auto* nsides = AiArrayAllocate(numFaces, 1, AI_TYPE_UINT); + auto* vidxs = AiArrayAllocate(vertexIndices.size(), 1, AI_TYPE_UINT); + for (auto i = decltype(numFaces){0}; i < numFaces; ++i) { + AiArraySetUInt(nsides, i, static_cast(vertexCounts[i])); + } + for (auto i = decltype(numVertexIndices){0}; i < numVertexIndices; ++i) { + AiArraySetUInt(vidxs, i, static_cast(vertexIndices[i])); + } + AiNodeSetArray(_shape.GetShape(), str::nsides, nsides); + AiNodeSetArray(_shape.GetShape(), str::vidxs, vidxs); + const auto scheme = topology.GetScheme(); + if (scheme == PxOsdOpenSubdivTokens->catmullClark || scheme == PxOsdOpenSubdivTokens->catmark) { + AiNodeSetStr(_shape.GetShape(), str::subdiv_type, str::catclark); + } else { + AiNodeSetStr(_shape.GetShape(), str::subdiv_type, str::none); + } + } + + if (HdChangeTracker::IsVisibilityDirty(*dirtyBits, id)) { + _UpdateVisibility(delegate, dirtyBits); + AiNodeSetByte(_shape.GetShape(), str::visibility, _sharedData.visible ? AI_RAY_ALL : uint8_t{0}); + } + + if (HdChangeTracker::IsDisplayStyleDirty(*dirtyBits, id)) { + const auto displayStyle = GetDisplayStyle(delegate); + AiNodeSetByte( + _shape.GetShape(), str::subdiv_iterations, static_cast(std::max(0, displayStyle.refineLevel))); + } + + if (HdChangeTracker::IsTransformDirty(*dirtyBits, id)) { + param->End(); + HdArnoldSetTransform(_shape.GetShape(), delegate, GetId()); + } + + if (HdChangeTracker::IsSubdivTagsDirty(*dirtyBits, id)) { + const auto subdivTags = GetSubdivTags(delegate); + const auto& cornerIndices = subdivTags.GetCornerIndices(); + const auto& cornerWeights = subdivTags.GetCornerWeights(); + const auto& creaseIndices = subdivTags.GetCreaseIndices(); + const auto& creaseLengths = subdivTags.GetCreaseLengths(); + const auto& creaseWeights = subdivTags.GetCreaseWeights(); + + const auto cornerIndicesCount = static_cast(cornerIndices.size()); + uint32_t cornerWeightCounts = 0; + for (auto creaseLength : creaseLengths) { + cornerWeightCounts += std::max(0, creaseLength - 1); + } + + const auto creaseIdxsCount = cornerIndicesCount * 2 + cornerWeightCounts * 2; + const auto craseSharpnessCount = cornerIndicesCount + cornerWeightCounts; + + auto* creaseIdxs = AiArrayAllocate(creaseIdxsCount, 1, AI_TYPE_UINT); + auto* creaseSharpness = AiArrayAllocate(craseSharpnessCount, 1, AI_TYPE_FLOAT); + + uint32_t ii = 0; + for (auto cornerIndex : cornerIndices) { + AiArraySetUInt(creaseIdxs, ii * 2, cornerIndex); + AiArraySetUInt(creaseIdxs, ii * 2 + 1, cornerIndex); + AiArraySetFlt(creaseSharpness, ii, cornerWeights[ii]); + ++ii; + } + + uint32_t jj = 0; + for (auto creaseLength : creaseLengths) { + for (auto k = decltype(creaseLength){1}; k < creaseLength; ++k, ++ii) { + AiArraySetUInt(creaseIdxs, ii * 2, creaseIndices[jj + k - 1]); + AiArraySetUInt(creaseIdxs, ii * 2 + 1, creaseIndices[jj + k]); + AiArraySetFlt(creaseSharpness, ii, creaseWeights[jj]); + } + jj += creaseLength; + } + + AiNodeSetArray(_shape.GetShape(), str::crease_idxs, creaseIdxs); + AiNodeSetArray(_shape.GetShape(), str::crease_sharpness, creaseSharpness); + } + + auto assignMaterial = [&](bool isVolume, const HdArnoldMaterial* material) { + if (material != nullptr) { + AiNodeSetPtr( + _shape.GetShape(), str::shader, isVolume ? material->GetVolumeShader() : material->GetSurfaceShader()); + AiNodeSetPtr(_shape.GetShape(), str::disp_map, material->GetDisplacementShader()); + } else { + AiNodeSetPtr( + _shape.GetShape(), str::shader, + isVolume ? _shape.GetDelegate()->GetFallbackVolumeShader() : _shape.GetDelegate()->GetFallbackShader()); + AiNodeSetPtr(_shape.GetShape(), str::disp_map, nullptr); + } + }; + + // Querying material for the second time will return an empty id, so we cache it. + const HdArnoldMaterial* arnoldMaterial = nullptr; + auto queryMaterial = [&]() -> const HdArnoldMaterial* { + return reinterpret_cast( + delegate->GetRenderIndex().GetSprim(HdPrimTypeTokens->material, delegate->GetMaterialId(id))); + }; + if (*dirtyBits & HdChangeTracker::DirtyMaterialId) { + param->End(); + arnoldMaterial = queryMaterial(); + assignMaterial(_IsVolume(), arnoldMaterial); + } + + // TODO: Implement all the primvars. + if (*dirtyBits & HdChangeTracker::DirtyPrimvar) { + param->End(); + // We are checking if the mesh was changed to volume or vice-versa. + const auto isVolume = _IsVolume(); + for (const auto& primvar : delegate->GetPrimvarDescriptors(id, HdInterpolation::HdInterpolationConstant)) { + HdArnoldSetConstantPrimvar(_shape.GetShape(), id, delegate, primvar); + } + // The mesh has changed, so we need to reassign materials. + if (isVolume != _IsVolume()) { + // Material ID wasn't dirtied, so we should query it. + if (arnoldMaterial == nullptr) { + arnoldMaterial = queryMaterial(); + } + assignMaterial(!isVolume, arnoldMaterial); + } + for (const auto& primvar : delegate->GetPrimvarDescriptors(id, HdInterpolation::HdInterpolationUniform)) { + HdArnoldSetUniformPrimvar(_shape.GetShape(), id, delegate, primvar); + } + for (const auto& primvar : delegate->GetPrimvarDescriptors(id, HdInterpolation::HdInterpolationVertex)) { + if (primvar.name == HdTokens->points) { + continue; + } else if (primvar.name == _tokens->st || primvar.name == _tokens->uv) { + const auto v = delegate->Get(id, primvar.name); + if (v.IsHolding>()) { + const auto& uv = v.UncheckedGet>(); + const auto numUVs = static_cast(uv.size()); + // Can assume uvs are flattened, with indices matching + // vert indices + auto* uvlist = AiArrayConvert(numUVs, 1, AI_TYPE_VECTOR2, uv.data()); + auto* uvidxs = AiArrayCopy(AiNodeGetArray(_shape.GetShape(), str::vidxs)); + + AiNodeSetArray(_shape.GetShape(), str::uvlist, uvlist); + AiNodeSetArray(_shape.GetShape(), str::uvidxs, uvidxs); + } else { + TF_WARN( + "[HdArnold] Primvar is named uv/st, but the type is not Vec2f on %s", + AiNodeGetName(_shape.GetShape())); + } + } else { + HdArnoldSetVertexPrimvar(_shape.GetShape(), id, delegate, primvar); + } + } + for (const auto& primvar : delegate->GetPrimvarDescriptors(id, HdInterpolation::HdInterpolationFaceVarying)) { + if (primvar.name == _tokens->st || primvar.name == _tokens->uv) { + const auto v = delegate->Get(id, primvar.name); + if (v.IsHolding>()) { + const auto& uv = v.UncheckedGet>(); + const auto numUVs = static_cast(uv.size()); + // Same memory layout and this data is flattened. + auto* uvlist = AiArrayConvert(numUVs, 1, AI_TYPE_VECTOR2, uv.data()); + auto* uvidxs = AiArrayAllocate(numUVs, 1, AI_TYPE_UINT); + for (auto i = decltype(numUVs){0}; i < numUVs; ++i) { + AiArraySetUInt(uvidxs, i, i); + } + AiNodeSetArray(_shape.GetShape(), str::uvlist, uvlist); + AiNodeSetArray(_shape.GetShape(), str::uvidxs, uvidxs); + } + } else { + HdArnoldSetFaceVaryingPrimvar(_shape.GetShape(), id, delegate, primvar); + } + } + } + + _shape.Sync(this, *dirtyBits, delegate, param); + + *dirtyBits = HdChangeTracker::Clean; +} + +HdDirtyBits HdArnoldMesh::GetInitialDirtyBitsMask() const +{ + return HdChangeTracker::Clean | HdChangeTracker::InitRepr | HdChangeTracker::DirtyPoints | + HdChangeTracker::DirtyTopology | HdChangeTracker::DirtyTransform | HdChangeTracker::DirtyMaterialId | + HdChangeTracker::DirtyPrimID | HdChangeTracker::DirtyPrimvar | HdChangeTracker::DirtyInstanceIndex | + HdChangeTracker::DirtyVisibility; +} + +HdDirtyBits HdArnoldMesh::_PropagateDirtyBits(HdDirtyBits bits) const { return bits & HdChangeTracker::AllDirty; } + +void HdArnoldMesh::_InitRepr(const TfToken& reprToken, HdDirtyBits* dirtyBits) +{ + TF_UNUSED(reprToken); + TF_UNUSED(dirtyBits); +} + +bool HdArnoldMesh::_IsVolume() const { return AiNodeGetFlt(_shape.GetShape(), str::step_size) > 0.0f; } + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/mesh.h b/render_delegate/mesh.h new file mode 100755 index 0000000000..82831db192 --- /dev/null +++ b/render_delegate/mesh.h @@ -0,0 +1,105 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/// @file mesh.h +/// +/// Utilities for translating Hydra Meshes for the Render Delegate. +#pragma once + +#include "api.h" + +#include + +#include + +#include + +#include "hdarnold.h" +#include "render_delegate.h" +#include "shape.h" + +PXR_NAMESPACE_OPEN_SCOPE + +/// Utility class for translating Hydra Mesh to Arnold Polymesh. +class HdArnoldMesh : public HdMesh { +public: + /// Constructor for HdArnoldMesh. + /// + /// @param delegate Pointer to the Render Delegate. + /// @param id Path to the mesh. + /// @param instancerId Path to the Point Instancer for this mesh. + HDARNOLD_API + HdArnoldMesh(HdArnoldRenderDelegate* delegate, const SdfPath& id, const SdfPath& instancerId = SdfPath()); + + /// Destructor for HdArnoldMesh. + /// + /// Destory all Arnold Polymeshes and Ginstances. + ~HdArnoldMesh() override = default; + + /// Syncs the Hydra Mesh to the Arnold Polymesh. + /// + /// @param sceneDelegate Pointer to the Scene Delegate. + /// @param renderPaaram Pointer to a HdArnoldRenderParam instance. + /// @param dirtyBits Dirty Bits to sync. + /// @param reprToken Token describing the representation of the mesh. + HDARNOLD_API + void Sync(HdSceneDelegate* delegate, HdRenderParam* renderParam, HdDirtyBits* dirtyBits, const TfToken& reprToken) + override; + + /// Returns the initial Dirty Bits for the Primitive. + /// + /// @return Initial Dirty Bits. + HDARNOLD_API + HdDirtyBits GetInitialDirtyBitsMask() const override; + +protected: + /// Allows setting additional Dirty Bits based on the ones already set. + /// + /// @param bits The current Dirty Bits. + /// @return The new set of Dirty Bits which replace the original one. + HDARNOLD_API + HdDirtyBits _PropagateDirtyBits(HdDirtyBits bits) const override; + + /// Initialize a given representation for the mesh. + /// + /// @param reprName Name of the representation to initialize. + /// @param dirtyBits In/Out HdDirtyBits value, that allows the _InitRepr + /// function to set additional Dirty Bits if required for a given + /// representation. + HDARNOLD_API + void _InitRepr(const TfToken& reprToken, HdDirtyBits* dirtyBits) override; + + /// Returns true if step size is bigger than zero, false otherwise. + /// + /// @return True if polymesh is a volume boundary. + HDARNOLD_API + bool _IsVolume() const; + + HdArnoldShape _shape; ///< Utility class for the mesh and instances. +}; + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/nodes/driver.cpp b/render_delegate/nodes/driver.cpp new file mode 100755 index 0000000000..d21ab0d2a5 --- /dev/null +++ b/render_delegate/nodes/driver.cpp @@ -0,0 +1,164 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include + +#include + +#include + +#include "../constant_strings.h" +#include "../utils.h" +#include "nodes.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +AI_DRIVER_NODE_EXPORT_METHODS(HdArnoldDriverMtd); + +AtString HdArnoldDriver::projMtx("projMtx"); +AtString HdArnoldDriver::viewMtx("viewMtx"); + +namespace { +const char* supportedExtensions[] = {nullptr}; + +struct DriverData { + GfMatrix4f projMtx; + GfMatrix4f viewMtx; +}; +} // namespace + +tbb::concurrent_queue bucketQueue; + +void hdArnoldEmptyBucketQueue(const std::function& f) +{ + HdArnoldBucketData* data = nullptr; + while (bucketQueue.try_pop(data)) { + if (data) { + f(data); + delete data; + data = nullptr; + } + } +} + +node_parameters +{ + AiParameterMtx(HdArnoldDriver::projMtx, AiM4Identity()); + AiParameterMtx(HdArnoldDriver::viewMtx, AiM4Identity()); +} + +node_initialize +{ + AiDriverInitialize(node, true); + AiNodeSetLocalData(node, new DriverData()); +} + +node_update +{ + auto* data = reinterpret_cast(AiNodeGetLocalData(node)); + data->projMtx = HdArnoldConvertMatrix(AiNodeGetMatrix(node, HdArnoldDriver::projMtx)); + data->viewMtx = HdArnoldConvertMatrix(AiNodeGetMatrix(node, HdArnoldDriver::viewMtx)); +} + +node_finish {} + +driver_supports_pixel_type +{ + return pixel_type == AI_TYPE_RGBA || pixel_type == AI_TYPE_VECTOR || pixel_type == AI_TYPE_UINT; +} + +driver_extension { return supportedExtensions; } + +driver_open {} + +driver_needs_bucket { return true; } + +driver_prepare_bucket {} + +driver_process_bucket +{ + const auto* driverData = reinterpret_cast(AiNodeGetLocalData(node)); + const char* outputName = nullptr; + int pixelType = AI_TYPE_RGBA; + const void* bucketData = nullptr; + auto* data = new HdArnoldBucketData(); + data->xo = bucket_xo; + data->yo = bucket_yo; + data->sizeX = bucket_size_x; + data->sizeY = bucket_size_y; + const auto bucketSize = bucket_size_x * bucket_size_y; + while (AiOutputIteratorGetNext(iterator, &outputName, &pixelType, &bucketData)) { + if (pixelType == AI_TYPE_RGBA && strcmp(outputName, "RGBA") == 0) { + data->beauty.resize(bucketSize); + const auto* inRGBA = reinterpret_cast(bucketData); + for (auto i = decltype(bucketSize){0}; i < bucketSize; ++i) { + const auto in = inRGBA[i]; + const auto x = bucket_xo + i % bucket_size_x; + const auto y = bucket_yo + i / bucket_size_x; + AtRGBA8 out; + out.r = AiQuantize8bit(x, y, 0, in.r, true); + out.g = AiQuantize8bit(x, y, 1, in.g, true); + out.b = AiQuantize8bit(x, y, 2, in.b, true); + out.a = AiQuantize8bit(x, y, 3, in.a, true); + data->beauty[i] = out; + } + + } else if (pixelType == AI_TYPE_VECTOR && strcmp(outputName, "P") == 0) { + data->depth.resize(bucketSize, 1.0f); + const auto* pp = reinterpret_cast(bucketData); + auto* pz = data->depth.data(); + for (auto i = decltype(bucketSize){0}; i < bucketSize; ++i) { + // Rays hitting the background will return a (0,0,0) vector. We don't worry about it, as background + // pixels will be marked with an ID of 0 by arnold. + const auto p = driverData->projMtx.Transform(driverData->viewMtx.Transform(pp[i])); + pz[i] = std::max(-1.0f, std::min(1.0f, p[2])); + } + } else if (pixelType == AI_TYPE_UINT && strcmp(outputName, "ID") == 0) { + data->primId.resize(bucketSize, -1); + // Technically, we're copying from an unsigned int buffer to a signed int buffer... but the values were + // originally force-reinterpreted to unsigned on the way in, so we're undoing that on the way out + memcpy(data->primId.data(), bucketData, bucketSize * sizeof(decltype(data->primId[0]))); + } + } + if (data->beauty.empty() || data->depth.empty() || data->primId.empty()) { + delete data; + } else { + for (auto i = decltype(bucketSize){0}; i < bucketSize; ++i) { + // The easiest way to filter is to check for the zero primID. + data->primId[i] -= 1; + if (data->primId[i] == -1) { + data->depth[i] = 1.0f - AI_EPSILON; + data->beauty[i].a = 0.0f; + } + } + bucketQueue.push(data); + } +} + +driver_write_bucket {} + +driver_close {} diff --git a/render_delegate/nodes/nodes.cpp b/render_delegate/nodes/nodes.cpp new file mode 100755 index 0000000000..334eb7e4ce --- /dev/null +++ b/render_delegate/nodes/nodes.cpp @@ -0,0 +1,68 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "nodes.h" + +#include +#include + +extern const AtNodeMethods* HdArnoldDriverMtd; + +AtString HdArnoldNodeNames::driver("HdArnoldDriver"); + +namespace { +struct NodeDefinition { + int type; + uint8_t outputType; + AtString& name; + const AtNodeMethods* methods; +}; + +using BuiltInNodes = std::vector; + +const auto builtInNodes = []() -> const BuiltInNodes& { + static const BuiltInNodes ret{ + {AI_NODE_DRIVER, AI_TYPE_UNDEFINED, HdArnoldNodeNames::driver, HdArnoldDriverMtd}, + }; + return ret; +}; + +} // namespace + +void hdArnoldInstallNodes() +{ + for (const auto& it : builtInNodes()) { + AiNodeEntryInstall(it.type, it.outputType, it.name, "", it.methods, AI_VERSION); + } +} + +void hdArnoldUninstallNodes() +{ + for (const auto& it : builtInNodes()) { + AiNodeEntryUninstall(it.name); + } +} diff --git a/render_delegate/nodes/nodes.h b/render_delegate/nodes/nodes.h new file mode 100755 index 0000000000..5230a3d252 --- /dev/null +++ b/render_delegate/nodes/nodes.h @@ -0,0 +1,96 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/// @file nodes.h +/// +/// Interfaces for Arnold nodes used by the Render Delegate. +#ifndef HDARNOLD_NODES_H +#define HDARNOLD_NODES_H + +#include + +#include +#include + +namespace HdArnoldNodeNames { +extern AtString driver; +} // namespace HdArnoldNodeNames + +namespace HdArnoldDriver { +extern AtString projMtx; +extern AtString viewMtx; +} // namespace HdArnoldDriver + +/// Installs Arnold nodes that are used by the Render Delegate. +void hdArnoldInstallNodes(); + +/// Uninstalls Arnold nodes that are used by the Render Delegate. +void hdArnoldUninstallNodes(); + +/// Simple structure holding a 4 component, 8 bit per component color. +struct AtRGBA8 { + uint8_t r = 0; ///< Red component of the color. + uint8_t g = 0; ///< Green component of the color. + uint8_t b = 0; ///< Blue component of the color. + uint8_t a = 0; ///< Alpha component of the color. +}; + +/// Structure holding rendered bucket data. +/// +/// HdArnoldBucketData holds the screen space coordinates of the bucket and +/// 8 bit beauty alongside a single precision floating point depth. +struct HdArnoldBucketData { + HdArnoldBucketData() = default; + ~HdArnoldBucketData() = default; + HdArnoldBucketData(const HdArnoldBucketData&) = delete; + HdArnoldBucketData(HdArnoldBucketData&&) = delete; + HdArnoldBucketData& operator=(const HdArnoldBucketData&) = delete; + + int xo = 0; ///< X pixel coordinate origin of the bucket. + int yo = 0; ///< Y pixel coorindate origin of the bucket. + int sizeX = 0; ///< Width of the bucket in pixels. + int sizeY = 0; ///< Height of the bucket in pixels. + + /// These values are dithered and quatized from the beauty AOV using + /// AiQuantize8bit. + std::vector beauty; ///< BeautyV of the rendered image. + + /// These values are computed from the P AOV and the projection matrix + /// provided by Hydra. + std::vector depth; ///< Depth of the rendered image. + + /// These values are computed from the ID AOV (and we set the id + /// attribute to the primId returned by Hydra). + std::vector primId; +}; + +/// Empties the bucket queue held by the driver. +/// +/// @param f Function object thar receives each bucket stored by the queue. +void hdArnoldEmptyBucketQueue(const std::function& f); + +#endif diff --git a/render_delegate/openvdb_asset.cpp b/render_delegate/openvdb_asset.cpp new file mode 100755 index 0000000000..4f529c3d40 --- /dev/null +++ b/render_delegate/openvdb_asset.cpp @@ -0,0 +1,63 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "openvdb_asset.h" + +#include +#include + +PXR_NAMESPACE_OPEN_SCOPE + +HdArnoldOpenvdbAsset::HdArnoldOpenvdbAsset(HdArnoldRenderDelegate* delegate, const SdfPath& id) : HdField(id) +{ + TF_UNUSED(delegate); +} + +void HdArnoldOpenvdbAsset::Sync(HdSceneDelegate* sceneDelegate, HdRenderParam* renderParam, HdDirtyBits* dirtyBits) +{ + TF_UNUSED(renderParam); + if (*dirtyBits & HdField::DirtyParams) { + auto& changeTracker = sceneDelegate->GetRenderIndex().GetChangeTracker(); + // But accessing this list happens on a single thread, + // as bprims are synced before rprims. + for (const auto& volume : _volumeList) { + changeTracker.MarkRprimDirty(volume, HdChangeTracker::DirtyTopology); + } + } + *dirtyBits = HdField::Clean; +} + +HdDirtyBits HdArnoldOpenvdbAsset::GetInitialDirtyBitsMask() const { return HdField::AllDirty; } + +// This will be called from multiple threads. +void HdArnoldOpenvdbAsset::TrackVolumePrimitive(const SdfPath& id) +{ + std::lock_guard lock(_volumeListMutex); + _volumeList.insert(id); +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/openvdb_asset.h b/render_delegate/openvdb_asset.h new file mode 100755 index 0000000000..f780a00a20 --- /dev/null +++ b/render_delegate/openvdb_asset.h @@ -0,0 +1,93 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/// @file openvdb_asset.h +/// +/// Utilities for translating Hydra Openvdb Assets for the Render Delegate. +/// TODO: +/// * Investigate what happens when the connection between the Hydra Volume +/// and the Hydra OpenVDB Asset is broken. +#pragma once + +#include +#include "api.h" + +#include + +#include "render_delegate.h" + +#include +#include + +PXR_NAMESPACE_OPEN_SCOPE + +/// Utility class for translating Hydra Openvdb Asset to Arnold Volume. +class HdArnoldOpenvdbAsset : public HdField { +public: + /// Constructor for HdArnoldOpenvdbAsset + /// + /// @param delegate Pointer to the Render Delegate. + /// @param id Path to the OpenVDB Asset. + HDARNOLD_API + HdArnoldOpenvdbAsset(HdArnoldRenderDelegate* delegate, const SdfPath& id); + + /// Syncing the Hydra Openvdb Asset to the Arnold Volume. + /// + /// The functions main purpose is to dirty every Volume primitive's + /// topology, so the grid definitions on the volume can be rebuilt, since + /// changing the the grid name on the openvdb asset doesn't dirty the + /// volume primitive, which holds the arnold volume shape. + /// + /// @param sceneDelegate Pointer to the Hydra Scene Delegate. + /// @param renderParam Pointer to a HdArnoldRenderParam instance. + /// @param dirtyBits Dirty Bits to sync. + HDARNOLD_API + void Sync(HdSceneDelegate* sceneDelegate, HdRenderParam* renderParam, HdDirtyBits* dirtyBits) override; + + /// Returns the initial Dirty Bits for the Primitive. + /// + /// @return Initial Dirty Bits. + HDARNOLD_API + HdDirtyBits GetInitialDirtyBitsMask() const override; + + /// Tracks a HdArnoldVolume primitive. + /// + /// Hydra separates the volume definitions from the grids each volume + /// requires, so we need to make sure each grid definition, which can be + /// shared between multiple volumes, knows which volume it belongs to. + /// + /// @param id Path to the Hydra Volume. + HDARNOLD_API + void TrackVolumePrimitive(const SdfPath& id); + +private: + std::mutex _volumeListMutex; ///< Lock for the _volumeList. + /// Storing all the Hydra Volumes using this asset. + std::unordered_set _volumeList; +}; + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/plugInfo.json.in b/render_delegate/plugInfo.json.in new file mode 100755 index 0000000000..4c13508c8d --- /dev/null +++ b/render_delegate/plugInfo.json.in @@ -0,0 +1,22 @@ +{ + "Plugins": [ + { + "Info": { + "Types": { + "HdArnoldRendererPlugin": { + "bases": [ + "${RENDERER_PLUGIN_BASE}" + ], + "displayName": "Arnold", + "priority": 99 + } + } + }, + "LibraryPath": "../hdArnold${LIB_EXTENSION}", + "Name": "hdArnold", + "ResourcePath": "resources", + "Root": "..", + "Type": "library" + } + ] +} diff --git a/render_delegate/points.cpp b/render_delegate/points.cpp new file mode 100755 index 0000000000..c0dc29952e --- /dev/null +++ b/render_delegate/points.cpp @@ -0,0 +1,137 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "points.h" + +#include "constant_strings.h" +#include "material.h" +#include "utils.h" + +PXR_NAMESPACE_OPEN_SCOPE + +namespace { + +template +inline void _SetMotionBlurredPrimvar( + HdSceneDelegate* delegate, const SdfPath& id, const TfToken& primvarName, AtNode* node, const AtString& paramName) +{ + constexpr size_t maxSamples = 2; + HdTimeSampleArray xf; + delegate->SamplePrimvar(id, primvarName, &xf); + if (xf.count > 0 && ARCH_LIKELY(xf.values[0].IsHolding>())) { + const auto& v0 = xf.values[0].Get>(); + if (xf.count > 1 && ARCH_UNLIKELY(!xf.values[1].IsHolding>())) { + xf.count = 1; + } + auto* arr = AiArrayAllocate(v0.size(), xf.count, AT); + AiArraySetKey(arr, 0, v0.data()); + if (xf.count > 1) { + const auto& v1 = xf.values[1].Get>(); + if (ARCH_LIKELY(v1.size() == v0.size())) { + AiArraySetKey(arr, 1, v1.data()); + } else { + AiArraySetKey(arr, 1, v0.data()); + } + } + AiNodeSetArray(node, paramName, arr); + } +} + +} // namespace + +HdArnoldPoints::HdArnoldPoints(HdArnoldRenderDelegate* delegate, const SdfPath& id, const SdfPath& instancerId) + : HdPoints(id, instancerId), _shape(str::points, delegate, id, GetPrimId()) +{ +} + +HdArnoldPoints::~HdArnoldPoints() {} + +HdDirtyBits HdArnoldPoints::GetInitialDirtyBitsMask() const +{ + return HdChangeTracker::DirtyPoints | HdChangeTracker::DirtyTransform | HdChangeTracker::DirtyVisibility | + HdChangeTracker::DirtyPrimvar | HdChangeTracker::DirtyWidths | HdChangeTracker::DirtyMaterialId | + HdChangeTracker::DirtyInstanceIndex; +} + +void HdArnoldPoints::Sync( + HdSceneDelegate* delegate, HdRenderParam* renderParam, HdDirtyBits* dirtyBits, const TfToken& reprToken) +{ + auto* param = reinterpret_cast(renderParam); + const auto& id = GetId(); + if (HdChangeTracker::IsPrimvarDirty(*dirtyBits, id, HdTokens->points)) { + param->End(); + HdArnoldSetPositionFromPrimvar(_shape.GetShape(), id, delegate, str::points); + // HdPrman exports points like this, but this method does not support + // motion blurred points. + } else if (*dirtyBits & HdChangeTracker::DirtyPoints) { + param->End(); + const auto pointsValue = delegate->Get(id, HdTokens->points); + if (!pointsValue.IsEmpty() && pointsValue.IsHolding()) { + const auto& points = pointsValue.UncheckedGet(); + auto* arr = AiArrayAllocate(points.size(), 1, AI_TYPE_VECTOR); + AiArraySetKey(arr, 0, points.data()); + AiNodeSetArray(_shape.GetShape(), str::points, arr); + } + } + + if (HdChangeTracker::IsPrimvarDirty(*dirtyBits, id, HdTokens->widths)) { + param->End(); + HdArnoldSetRadiusFromPrimvar(_shape.GetShape(), id, delegate); + } + + if (HdChangeTracker::IsVisibilityDirty(*dirtyBits, id)) { + _UpdateVisibility(delegate, dirtyBits); + AiNodeSetByte(_shape.GetShape(), str::visibility, _sharedData.visible ? AI_RAY_ALL : uint8_t{0}); + } + + if (*dirtyBits & HdChangeTracker::DirtyMaterialId) { + param->End(); + const auto* material = reinterpret_cast( + delegate->GetRenderIndex().GetSprim(HdPrimTypeTokens->material, delegate->GetMaterialId(id))); + if (material != nullptr) { + AiNodeSetPtr(_shape.GetShape(), str::shader, material->GetSurfaceShader()); + } else { + AiNodeSetPtr(_shape.GetShape(), str::shader, _shape.GetDelegate()->GetFallbackShader()); + } + } + + if (*dirtyBits & HdChangeTracker::DirtyPrimvar) { + param->End(); + for (const auto& primvar : delegate->GetPrimvarDescriptors(id, HdInterpolation::HdInterpolationConstant)) { + HdArnoldSetConstantPrimvar(_shape.GetShape(), id, delegate, primvar); + } + + for (const auto& primvar : delegate->GetPrimvarDescriptors(id, HdInterpolation::HdInterpolationVertex)) { + if (primvar.name == HdTokens->points || primvar.name == HdTokens->widths) { + continue; + } else { + // Per vertex attributes uniform on points. + HdArnoldSetUniformPrimvar(_shape.GetShape(), id, delegate, primvar); + } + } + } + + _shape.Sync(this, *dirtyBits, delegate, param); + + *dirtyBits = HdChangeTracker::Clean; +} + +HdDirtyBits HdArnoldPoints::_PropagateDirtyBits(HdDirtyBits bits) const { return bits & HdChangeTracker::AllDirty; } + +void HdArnoldPoints::_InitRepr(const TfToken& reprToken, HdDirtyBits* dirtyBits) +{ + TF_UNUSED(reprToken); + TF_UNUSED(dirtyBits); +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/points.h b/render_delegate/points.h new file mode 100755 index 0000000000..1a95270f15 --- /dev/null +++ b/render_delegate/points.h @@ -0,0 +1,85 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/// @file points.h +/// +/// Utility class to support point primitives in Hydra. +#pragma once + +#include "api.h" + +#include + +#include + +#include + +#include "render_delegate.h" +#include "shape.h" + +PXR_NAMESPACE_OPEN_SCOPE + +/// Utility class to handle point primitives. +class HdArnoldPoints : public HdPoints { +public: + /// Constructor for HdArnoldPoints. + /// + /// @param delegate Pointer to the Render Delegate. + /// @param id Path to the points. + /// @param instancerId Path to the Point Instancer for this points. + HDARNOLD_API + HdArnoldPoints(HdArnoldRenderDelegate* delegate, const SdfPath& id, const SdfPath& instancerId = SdfPath()); + + /// Destructor for HdArnoldPoints. + /// + /// Destory all Arnold Points and Ginstances. + HDARNOLD_API + ~HdArnoldPoints(); + + /// Returns the initial Dirty Bits for the Primitive. + /// + /// @return Initial Dirty Bits. + HDARNOLD_API + HdDirtyBits GetInitialDirtyBitsMask() const override; + + /// Syncs the Hydra Points to the Arnold Points. + /// + /// @param sceneDelegate Pointer to the Scene Delegate. + /// @param renderPaaram Pointer to a HdArnoldRenderParam instance. + /// @param dirtyBits Dirty Bits to sync. + /// @param reprToken Token describing the representation of the points. + HDARNOLD_API + void Sync(HdSceneDelegate* delegate, HdRenderParam* renderParam, HdDirtyBits* dirtyBits, const TfToken& reprToken) + override; + +protected: + /// Allows setting additional Dirty Bits based on the ones already set. + /// + /// @param bits The current Dirty Bits. + /// @return The new set of Dirty Bits which replace the original one. + HDARNOLD_API + HdDirtyBits _PropagateDirtyBits(HdDirtyBits bits) const override; + + /// Initialize a given representation for the points. + /// + /// @param reprName Name of the representation to initialize. + /// @param dirtyBits In/Out HdDirtyBits value, that allows the _InitRepr + /// function to set additional Dirty Bits if required for a given + /// representation. + HDARNOLD_API + void _InitRepr(const TfToken& reprToken, HdDirtyBits* dirtyBits) override; + + HdArnoldShape _shape; ///< Utility class for the points and the instances. +}; + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/render_buffer.cpp b/render_delegate/render_buffer.cpp new file mode 100755 index 0000000000..61398be69c --- /dev/null +++ b/render_delegate/render_buffer.cpp @@ -0,0 +1,191 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "render_buffer.h" + +#include "pxr/base/gf/vec2i.h" +#include "pxr/base/gf/vec3i.h" + +PXR_NAMESPACE_OPEN_SCOPE + +namespace { +template +void _ConvertPixel(HdFormat dstFormat, uint8_t* dst, HdFormat srcFormat, uint8_t const* src) +{ + HdFormat srcComponentFormat = HdGetComponentFormat(srcFormat); + HdFormat dstComponentFormat = HdGetComponentFormat(dstFormat); + size_t srcComponentCount = HdGetComponentCount(srcFormat); + size_t dstComponentCount = HdGetComponentCount(dstFormat); + + for (size_t c = 0; c < dstComponentCount; ++c) { + T readValue = 0; + if (c < srcComponentCount) { + if (srcComponentFormat == HdFormatInt32) { + readValue = ((int32_t*)src)[c]; + } else if (srcComponentFormat == HdFormatFloat16) { + GfHalf half; + half.setBits(((uint16_t*)src)[c]); + readValue = static_cast(half); + } else if (srcComponentFormat == HdFormatFloat32) { + readValue = ((float*)src)[c]; + } else if (srcComponentFormat == HdFormatUNorm8) { + readValue = ((uint8_t*)src)[c] / 255.0f; + } else if (srcComponentFormat == HdFormatSNorm8) { + readValue = ((int8_t*)src)[c] / 127.0f; + } + } + + if (dstComponentFormat == HdFormatInt32) { + ((int32_t*)dst)[c] = readValue; + } else if (dstComponentFormat == HdFormatFloat16) { + ((uint16_t*)dst)[c] = GfHalf(float(readValue)).bits(); + } else if (dstComponentFormat == HdFormatFloat32) { + ((float*)dst)[c] = readValue; + } else if (dstComponentFormat == HdFormatUNorm8) { + ((uint8_t*)dst)[c] = (readValue * 255.0f); + } else if (dstComponentFormat == HdFormatSNorm8) { + ((int8_t*)dst)[c] = (readValue * 127.0f); + } + } +} +} // namespace + +HdArnoldRenderBuffer::HdArnoldRenderBuffer(const SdfPath& id) + : HdRenderBuffer(id), _width(0), _height(0), _format(HdFormatInvalid), _mappers(0), _converged(false) +{ +} + +bool HdArnoldRenderBuffer::Allocate(const GfVec3i& dimensions, HdFormat format, bool multiSampled) +{ + _Deallocate(); + + if (dimensions[2] != 1) { + TF_WARN( + "Render buffer allocated with dims <%d, %d, %d> and format %s; depth must be 1!", dimensions[0], + dimensions[1], dimensions[2], TfEnum::GetName(format).c_str()); + return false; + } + + _width = dimensions[0]; + _height = dimensions[1]; + _format = format; + _buffer.resize(_width * _height * HdDataSizeOfFormat(format)); + + return true; +} + +unsigned int HdArnoldRenderBuffer::GetWidth() const { return _width; } + +unsigned int HdArnoldRenderBuffer::GetHeight() const { return _height; } + +unsigned int HdArnoldRenderBuffer::GetDepth() const { return 1; } + +HdFormat HdArnoldRenderBuffer::GetFormat() const { return _format; } + +bool HdArnoldRenderBuffer::IsMultiSampled() const { return false; } + +#if USED_USD_VERSION_GREATER_EQ(19, 10) +void* HdArnoldRenderBuffer::Map() +#else +uint8_t* HdArnoldRenderBuffer::Map() +#endif +{ + _mappers++; + return _buffer.data(); +} + +void HdArnoldRenderBuffer::Unmap() { _mappers--; } + +bool HdArnoldRenderBuffer::IsMapped() const { return _mappers.load() != 0; } + +void HdArnoldRenderBuffer::Resolve() {} + +bool HdArnoldRenderBuffer::IsConverged() const { return _converged.load(); } + +void HdArnoldRenderBuffer::SetConverged(bool cv) { _converged.store(cv); } + +void HdArnoldRenderBuffer::Blit(HdFormat format, int width, int height, int offset, int stride, uint8_t const* data) +{ + size_t pixelSize = HdDataSizeOfFormat(_format); + if (_format == format) { + if (static_cast(width) == _width && static_cast(height) == _height) { + // Awesome! Blit line by line. + for (unsigned int j = 0; j < _height; ++j) { + memcpy( + &_buffer[(j * _width) * pixelSize], &data[(j * stride + offset) * pixelSize], _width * pixelSize); + } + } else { + // Ok... Blit pixel by pixel, with nearest point sampling. + float scalei = width / float(_width); + float scalej = height / float(_height); + for (unsigned int j = 0; j < _height; ++j) { + for (unsigned int i = 0; i < _width; ++i) { + unsigned int ii = scalei * i; + unsigned int jj = scalej * j; + memcpy( + &_buffer[(j * _width + i) * pixelSize], &data[(jj * stride + offset + ii) * pixelSize], + pixelSize); + } + } + } + } else { + // D'oh. Convert pixel by pixel, with nearest point sampling. + // If src and dst are both int-based, don't round trip to float. + bool convertAsInt = + (HdGetComponentFormat(format) == HdFormatInt32) && (HdGetComponentFormat(_format) == HdFormatInt32); + + float scalei = width / float(_width); + float scalej = height / float(_height); + for (unsigned int j = 0; j < _height; ++j) { + for (unsigned int i = 0; i < _width; ++i) { + unsigned int ii = scalei * i; + unsigned int jj = scalej * j; + if (convertAsInt) { + _ConvertPixel( + _format, static_cast(&_buffer[(j * _width + i) * pixelSize]), format, + &data[(jj * stride + offset + ii) * pixelSize]); + } else { + _ConvertPixel( + _format, static_cast(&_buffer[(j * _width + i) * pixelSize]), format, + &data[(jj * stride + offset + ii) * pixelSize]); + } + } + } + } +} + +void HdArnoldRenderBuffer::_Deallocate() +{ + _width = 0; + _height = 0; + _format = HdFormatInvalid; + _buffer.resize(0); + _mappers.store(0); + _converged.store(false); +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/render_buffer.h b/render_delegate/render_buffer.h new file mode 100755 index 0000000000..dd190d7ae6 --- /dev/null +++ b/render_delegate/render_buffer.h @@ -0,0 +1,149 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/// @file render_buffer.h +/// +/// Utilities for handling Hydra Render Buffers. +#pragma once + +#include + +#include "../arnold_usd.h" +#include "api.h" + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +/// Utility class for handling Hydra Render Buffers. +/// +/// The HdRenderBuffer is for handling 2d images for render output. Since this +/// is handled by the Arnold Core, HdArnoldRenderBuffer is reimplementing the +/// HdRenderBuffer class without doing or allocating anything. +class HdArnoldRenderBuffer : public HdRenderBuffer { +public: + /// Constructor for HdArnoldRenderBuffer. + /// + /// @param id Path to the Render Buffer Primitive. + HDARNOLD_API + HdArnoldRenderBuffer(const SdfPath& id); + /// Destructor for HdArnoldRenderBuffer. + HDARNOLD_API + ~HdArnoldRenderBuffer() override = default; + + /// Allocates the memory used by the render buffer. + /// + /// Does nothing. + /// + /// @param dimensions 3 Dimension Vector describing the dimensions of the + /// render buffer. + /// @param format HdFormat specifying the format of the Render Buffer. + /// @param multiSampled Boolean to indicate if the Render Buffer is + /// multisampled. + /// @return Boolean to indicate if allocation was successful, always false. + HDARNOLD_API + bool Allocate(const GfVec3i& dimensions, HdFormat format, bool multiSampled) override; + + /// Returns the width of the Render Buffer. + /// + /// @return Width of the Render Buffer, always 0. + HDARNOLD_API + unsigned int GetWidth() const override; + /// Returns the height of the Render Buffer. + /// + /// @return Height of the Render Buffer, always 0. + HDARNOLD_API + unsigned int GetHeight() const override; + /// Returns the depth of the Render Buffer, always 0. + /// + /// @return Depth of the Render Buffer. + HDARNOLD_API + unsigned int GetDepth() const override; + /// Returns the format of the Render Buffer. + /// + /// @return Format of the Render Buffer, always UNorm8. + HDARNOLD_API + HdFormat GetFormat() const override; + /// Returns true of if the Render Buffer is multi-sampled, false otherwise. + /// + /// @return Boolean indicating if the Render Buffer is multi-sampled, always + /// false. + HDARNOLD_API + bool IsMultiSampled() const override; + /// Maps the Render Buffer to the system memory. + /// + /// @return Pointer to the Render Buffer mapped to system memory. + HDARNOLD_API +#if USED_USD_VERSION_GREATER_EQ(19, 10) + void* Map() override; +#else + uint8_t* Map() override; +#endif + /// Unmaps the Render Buffer from the system memory. + HDARNOLD_API + void Unmap() override; + /// Returns true if the Render Buffer is mapped to system memory. + /// + /// @return Boolean indicating if the Render Buffer is mapped to system + /// memory. + HDARNOLD_API + bool IsMapped() const override; + + /// Resolve the buffer so that reads reflect the latest writes. + /// + /// Does nothing. + HDARNOLD_API + void Resolve() override; + /// Return whether the buffer is converged or not. + HDARNOLD_API + bool IsConverged() const override; + /// Sets whether the buffer is converged or not. + void SetConverged(bool cv); + + /// Helper to blit the render buffer to data + /// + /// format is the input format + void Blit(HdFormat format, int width, int height, int offset, int stride, uint8_t const* data); + +protected: + /// Deallocate memory allocated by the Render Buffer. + /// + /// Does nothing. + HDARNOLD_API + void _Deallocate() override; + +private: + unsigned int _width; + unsigned int _height; + HdFormat _format; + + std::vector _buffer; + std::atomic _mappers; + std::atomic _converged; +}; + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/render_delegate.cpp b/render_delegate/render_delegate.cpp new file mode 100755 index 0000000000..ad9468890d --- /dev/null +++ b/render_delegate/render_delegate.cpp @@ -0,0 +1,669 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "render_delegate.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "constant_strings.h" +#include "instancer.h" +#include "light.h" +#include "material.h" +#include "mesh.h" +#include "nodes/nodes.h" +#include "openvdb_asset.h" +#include "points.h" +#include "render_buffer.h" +#include "render_pass.h" +#include "volume.h" + +PXR_NAMESPACE_OPEN_SCOPE + +// Putting the ifdef inside the define private tokens drives MSVC crazy, while +// it works fine with clang and gcc. +// clang-format off +#ifdef BUILD_HOUDINI_TOOLS +TF_DEFINE_PRIVATE_TOKENS(_tokens, + (arnold) + (openvdbAsset) + (bprimHoudiniFieldAsset) +); +#else +TF_DEFINE_PRIVATE_TOKENS(_tokens, + (arnold) + (openvdbAsset) +); +#endif +// clang-format on + +namespace { + +VtValue _GetNodeParamValue(AtNode* node, const AtParamEntry* pentry) +{ + if (Ai_unlikely(pentry == nullptr)) { + return {}; + } + const auto ptype = AiParamGetType(pentry); + if (ptype == AI_TYPE_INT) { + return VtValue(AiNodeGetInt(node, AiParamGetName(pentry))); + } else if (ptype == AI_TYPE_FLOAT) { + return VtValue(AiNodeGetFlt(node, AiParamGetName(pentry))); + } else if (ptype == AI_TYPE_BOOLEAN) { + return VtValue(AiNodeGetBool(node, AiParamGetName(pentry))); + } else if (ptype == AI_TYPE_STRING || ptype == AI_TYPE_ENUM) { + return VtValue(std::string(AiNodeGetStr(node, AiParamGetName(pentry)))); + } + return {}; +} + +void _SetNodeParam(AtNode* node, const TfToken& key, const VtValue& value) +{ + // Some applications might send integers instead of booleans. + if (value.IsHolding()) { + const auto* nodeEntry = AiNodeGetNodeEntry(node); + auto* paramEntry = AiNodeEntryLookUpParameter(nodeEntry, key.GetText()); + if (paramEntry != nullptr) { + const auto paramType = AiParamGetType(paramEntry); + if (paramType == AI_TYPE_INT) { + AiNodeSetInt(node, key.GetText(), value.UncheckedGet()); + } else if (paramType == AI_TYPE_BOOLEAN) { + AiNodeSetBool(node, key.GetText(), value.UncheckedGet() != 0 ? true : false); + } + } + // Or longs. + } else if (value.IsHolding()) { + const auto* nodeEntry = AiNodeGetNodeEntry(node); + auto* paramEntry = AiNodeEntryLookUpParameter(nodeEntry, key.GetText()); + if (paramEntry != nullptr) { + const auto paramType = AiParamGetType(paramEntry); + if (paramType == AI_TYPE_INT) { + AiNodeSetInt(node, key.GetText(), value.UncheckedGet()); + } else if (paramType == AI_TYPE_BOOLEAN) { + AiNodeSetBool(node, key.GetText(), value.UncheckedGet() != 0 ? true : false); + } + } + } else if (value.IsHolding()) { + AiNodeSetFlt(node, key.GetText(), value.UncheckedGet()); + } else if (value.IsHolding()) { + AiNodeSetFlt(node, key.GetText(), static_cast(value.UncheckedGet())); + } else if (value.IsHolding()) { + AiNodeSetBool(node, key.GetText(), value.UncheckedGet()); + } else if (value.IsHolding()) { + AiNodeSetStr(node, key.GetText(), value.UncheckedGet().c_str()); + } else if (value.IsHolding()) { + AiNodeSetStr(node, key.GetText(), value.UncheckedGet().GetText()); + } +} + +inline const TfTokenVector& _SupportedRprimTypes() +{ + static const TfTokenVector r{HdPrimTypeTokens->mesh, HdPrimTypeTokens->volume, HdPrimTypeTokens->points}; + return r; +} + +inline const TfTokenVector& _SupportedSprimTypes() +{ + static const TfTokenVector r{HdPrimTypeTokens->camera, HdPrimTypeTokens->material, + HdPrimTypeTokens->distantLight, HdPrimTypeTokens->sphereLight, + HdPrimTypeTokens->diskLight, HdPrimTypeTokens->rectLight, + HdPrimTypeTokens->cylinderLight, HdPrimTypeTokens->domeLight, + /*HdPrimTypeTokens->simpleLight*/}; + return r; +} + +inline const TfTokenVector& _SupportedBprimTypes() +{ + static const TfTokenVector r{HdPrimTypeTokens->renderBuffer, _tokens->openvdbAsset +#ifdef BUILD_HOUDINI_TOOLS + , + _tokens->bprimHoudiniFieldAsset +#endif + }; + return r; +} + +struct SupportedRenderSetting { + /// Constructor with no default value. + SupportedRenderSetting(const char* _label) : label(_label) {} + + /// Constructor with a default value. + template + SupportedRenderSetting(const char* _label, const T& _defaultValue) : label(_label), defaultValue(_defaultValue) + { + } + + TfToken label; + VtValue defaultValue; +}; + +using SupportedRenderSettings = std::vector>; + +const SupportedRenderSettings& _GetSupportedRenderSettings() +{ + static const auto& config = HdArnoldConfig::GetInstance(); + static const SupportedRenderSettings data{ + // Global settings to control rendering + {str::t_enable_progressive_render, {"Enable Progressive Render", config.enable_progressive_render}}, + {str::t_progressive_min_AA_samples, {"Progressive Render Minimum AA Samples", config.progressive_min_AA_samples}}, + {str::t_enable_adaptive_sampling, {"Enable Adaptive Sampling", config.enable_adaptive_sampling}}, +#ifndef __APPLE__ + {str::t_enable_gpu_rendering, {"Enable GPU Rendering", config.enable_gpu_rendering}}, +#endif + {str::t_interactive_target_fps, {"Target FPS for Interactive Rendering", config.interactive_target_fps}}, + {str::t_interactive_target_fps_min, + {"Minimum Target FPS for Interactive Rendering", config.interactive_target_fps_min}}, + {str::t_interactive_fps_min, {"Minimum FPS for Interactive Rendering", config.interactive_fps_min}}, + // Threading settings + {str::t_threads, {"Number of Threads", config.threads}}, + // Sampling settings + {str::t_AA_samples, {"AA Samples", config.AA_samples}}, + {str::t_AA_samples_max, {"AA Samples Max"}}, + {str::t_GI_diffuse_samples, {"Diffuse Samples", config.GI_diffuse_samples}}, + {str::t_GI_specular_samples, {"Specular Samples", config.GI_specular_samples}}, + {str::t_GI_transmission_samples, {"Transmission Samples", config.GI_transmission_samples}}, + {str::t_GI_sss_samples, {"SubSurface Scattering Samples", config.GI_sss_samples}}, + {str::t_GI_volume_samples, {"Volume Samples", config.GI_volume_samples}}, + // Depth settings + {str::t_auto_transparency_depth, {"Auto Transparency Depth"}}, + {str::t_GI_diffuse_depth, {"Diffuse Depth", config.GI_diffuse_depth}}, + {str::t_GI_specular_depth, {"Specular Depth", config.GI_specular_depth}}, + {str::t_GI_transmission_depth, {"Transmission Depth"}}, + {str::t_GI_volume_depth, {"Volume Depth"}}, + {str::t_GI_total_depth, {"Total Depth"}}, + // Ignore settings + {str::t_ignore_textures, {"Ignore Textures"}}, + {str::t_ignore_shaders, {"Ignore Shaders"}}, + {str::t_ignore_atmosphere, {"Ignore Atmosphere"}}, + {str::t_ignore_lights, {"Ignore Lights"}}, + {str::t_ignore_shadows, {"Ignore Shadows"}}, + {str::t_ignore_subdivision, {"Ignore Subdivision"}}, + {str::t_ignore_displacement, {"Ignore Displacement"}}, + {str::t_ignore_bump, {"Ignore Bump"}}, + {str::t_ignore_motion, {"Ignore Motion"}}, + {str::t_ignore_motion_blur, {"Ignore Motion Blur"}}, + {str::t_ignore_dof, {"Ignore Depth of Field"}}, + {str::t_ignore_smoothing, {"Ignore Smoothing"}}, + {str::t_ignore_sss, {"Ignore SubSurface Scattering"}}, + {str::t_ignore_operators, {"Ignore Operators"}}, + // Log Settings + {str::t_log_verbosity, {"Log Verbosity (0-5)", config.log_verbosity}}, + {str::t_log_file, {"Log File Path", config.log_file}}, + // Profiling Settings + {str::t_profile_file, {"File Output for Profiling", config.profile_file}}, + }; + return data; +} + +int _GetLogFlagsFromVerbosity(int verbosity) +{ + if (verbosity <= 0) { + return 0; + } + if (verbosity >= 5) { + return AI_LOG_ALL & ~AI_LOG_COLOR; + } + + int flags = AI_LOG_ERRORS | AI_LOG_TIMESTAMP | AI_LOG_MEMORY | AI_LOG_BACKTRACE; + + if (verbosity >= 2) { + flags |= AI_LOG_WARNINGS; + if (verbosity >= 3) { + // Don't want progress without info, as otherwise it never prints a + // "render done" message! + flags |= AI_LOG_INFO | AI_LOG_PROGRESS; + if (verbosity >= 4) { + flags |= AI_LOG_STATS | AI_LOG_PLUGINS; + } + } + } + return flags; +} + +int _GetLogVerbosityFromFlags(int flags) +{ + // This isn't an exact mapping, as verbosity can't emcompass all possible + // flag combinations... so we just check for certain flags, and assume + if (flags == 0) { + return 0; + }; + if (flags & AI_LOG_DEBUG) { + return 5; + } + if (flags & (AI_LOG_STATS | AI_LOG_PLUGINS)) { + return 4; + } + if (flags & (AI_LOG_INFO | AI_LOG_PROGRESS)) { + return 3; + } + if (flags & (AI_LOG_WARNINGS)) { + return 2; + } + return 1; +} + +template +void _CheckForBoolValue(const VtValue& value, F&& f) +{ + if (value.IsHolding()) { + f(value.UncheckedGet()); + } else if (value.IsHolding()) { + f(value.UncheckedGet() != 0); + } else if (value.IsHolding()) { + f(value.UncheckedGet() != 0); + } +} + +template +void _CheckForIntValue(const VtValue& value, F&& f) +{ + if (value.IsHolding()) { + f(value.UncheckedGet()); + } else if (value.IsHolding()) { + f(static_cast(value.UncheckedGet())); + } +} + +} // namespace + +std::mutex HdArnoldRenderDelegate::_mutexResourceRegistry; +std::atomic_int HdArnoldRenderDelegate::_counterResourceRegistry; +HdResourceRegistrySharedPtr HdArnoldRenderDelegate::_resourceRegistry; + +HdArnoldRenderDelegate::HdArnoldRenderDelegate() +{ + _id = SdfPath(TfToken(TfStringPrintf("/HdArnoldRenderDelegate_%p", this))); + if (AiUniverseIsActive()) { + TF_CODING_ERROR("There is already an active Arnold universe!"); + } + AiBegin(AI_SESSION_INTERACTIVE); + std::lock_guard guard(_mutexResourceRegistry); + if (_counterResourceRegistry.fetch_add(1) == 0) { + _resourceRegistry.reset(new HdResourceRegistry()); + } + + const auto& config = HdArnoldConfig::GetInstance(); + if (config.log_flags_console >= 0) { + _ignoreVerbosityLogFlags = true; + AiMsgSetConsoleFlags(config.log_flags_console); + } else { + AiMsgSetConsoleFlags(_verbosityLogFlags); + } + if (config.log_flags_file >= 0) { + AiMsgSetLogFileFlags(config.log_flags_file); + } + hdArnoldInstallNodes(); + const auto arnoldPluginPath = TfGetenv("ARNOLD_PLUGIN_PATH"); + if (!arnoldPluginPath.empty()) { + AiLoadPlugins(arnoldPluginPath.c_str()); + } + + _universe = nullptr; + + _options = AiUniverseGetOptions(_universe); + for (const auto& o : _GetSupportedRenderSettings()) { + _SetRenderSetting(o.first, o.second.defaultValue); + } + + _fallbackShader = AiNode(_universe, "utility"); + AiNodeSetStr(_fallbackShader, str::name, TfStringPrintf("fallbackShader_%p", _fallbackShader).c_str()); + AiNodeSetStr(_fallbackShader, "shade_mode", "ambocc"); + AiNodeSetStr(_fallbackShader, "color_mode", "color"); + auto* userDataReader = AiNode(_universe, "user_data_rgb"); + AiNodeSetStr(userDataReader, "attribute", "displayColor"); + AiNodeSetRGB(userDataReader, "default", 1.0f, 1.0f, 1.0f); + AiNodeLink(userDataReader, "color", _fallbackShader); + + _fallbackVolumeShader = AiNode(_universe, "standard_volume"); + AiNodeSetStr(_fallbackVolumeShader, str::name, TfStringPrintf("fallbackVolume_%p", _fallbackVolumeShader).c_str()); + + _renderParam.reset(new HdArnoldRenderParam()); + + // AiRenderSetHintBool(str::progressive, true); + // We need access to both beauty and P at the same time. + AiRenderSetHintBool(str::progressive_show_all_outputs, true); +} + +HdArnoldRenderDelegate::~HdArnoldRenderDelegate() +{ + std::lock_guard guard(_mutexResourceRegistry); + if (_counterResourceRegistry.fetch_sub(1) == 1) { + _resourceRegistry.reset(); + } + _renderParam->End(); + hdArnoldUninstallNodes(); + AiUniverseDestroy(_universe); + AiEnd(); +} + +HdRenderParam* HdArnoldRenderDelegate::GetRenderParam() const { return _renderParam.get(); } + +void HdArnoldRenderDelegate::CommitResources(HdChangeTracker* tracker) { TF_UNUSED(tracker); } + +const TfTokenVector& HdArnoldRenderDelegate::GetSupportedRprimTypes() const { return _SupportedRprimTypes(); } + +const TfTokenVector& HdArnoldRenderDelegate::GetSupportedSprimTypes() const { return _SupportedSprimTypes(); } + +const TfTokenVector& HdArnoldRenderDelegate::GetSupportedBprimTypes() const { return _SupportedBprimTypes(); } + +void HdArnoldRenderDelegate::_SetRenderSetting(const TfToken& key, const VtValue& _value) +{ + // Currently usdview can return double for floats, so until it's fixed + // we have to convert doubles to float. + auto value = _value.IsHolding() ? VtValue(static_cast(_value.UncheckedGet())) : _value; + // Certain applications might pass boolean values via ints or longs. + if (key == str::t_enable_gpu_rendering) { + _CheckForBoolValue(value, [&] (const bool b) { + AiNodeSetStr(_options, str::render_device, b ? str::GPU : str::CPU); + AiDeviceAutoSelect(); + }); + } else if (key == str::t_log_verbosity) { + if (value.IsHolding()) { + _verbosityLogFlags = _GetLogFlagsFromVerbosity(value.UncheckedGet()); + if (!_ignoreVerbosityLogFlags) { + AiMsgSetConsoleFlags(_verbosityLogFlags); + } + } + } else if (key == str::t_log_file) { + if (value.IsHolding()) { + _logFile = value.UncheckedGet(); + AiMsgSetLogFileName(_logFile.c_str()); + } + } else if (key == str::t_enable_progressive_render) { + _CheckForBoolValue(value, [&](const bool b) { + AiRenderSetHintBool(str::progressive, b); + AiNodeSetBool(_options, str::enable_progressive_render, b); + }); + } else if (key == str::t_progressive_min_AA_samples) { + _CheckForIntValue(value, [&](const int i) { AiRenderSetHintInt(str::progressive_min_AA_samples, i); }); + } else if (key == str::t_interactive_target_fps) { + if (value.IsHolding()) { + AiRenderSetHintFlt(str::interactive_target_fps, value.UncheckedGet()); + } + } else if (key == str::t_interactive_target_fps_min) { + if (value.IsHolding()) { + AiRenderSetHintFlt(str::interactive_target_fps_min, value.UncheckedGet()); + } + } else if (key == str::t_interactive_fps_min) { + if (value.IsHolding()) { + AiRenderSetHintFlt(str::interactive_fps_min, value.UncheckedGet()); + } + } else if (key == str::t_profile_file) { + if (value.IsHolding()) { + AiProfileSetFileName(value.UncheckedGet().c_str()); + } + } else { + auto* optionsEntry = AiNodeGetNodeEntry(_options); + // Sometimes the Render Delegate receives parameters that don't exist + // on the options node. For example, if the host application ignores the + // render setting descriptor list. + if (AiNodeEntryLookUpParameter(optionsEntry, key.GetText()) != nullptr) { + _SetNodeParam(_options, key, value); + } + } +} + +void HdArnoldRenderDelegate::SetRenderSetting(const TfToken& key, const VtValue& value) +{ + _renderParam->End(); + _SetRenderSetting(key, value); +} + +VtValue HdArnoldRenderDelegate::GetRenderSetting(const TfToken& key) const +{ + if (key == str::t_enable_gpu_rendering) { + return VtValue(AiNodeGetStr(_options, str::render_device) == str::GPU); + } else if (key == str::t_enable_progressive_render) { + bool v = true; + AiRenderGetHintBool(str::progressive, v); + return VtValue(v); + } else if (key == str::progressive_min_AA_samples) { + int v = -4; + AiRenderGetHintInt(str::progressive_min_AA_samples, v); + return VtValue(v); + } else if (key == str::t_log_verbosity) { + return VtValue(_GetLogVerbosityFromFlags(_verbosityLogFlags)); + } else if (key == str::t_log_file) { + return VtValue(_logFile); + } else if (key == str::t_interactive_target_fps) { + float v = 1.0f; + AiRenderGetHintFlt(str::interactive_target_fps, v); + return VtValue(v); + } else if (key == str::t_interactive_target_fps_min) { + float v = 1.0f; + AiRenderGetHintFlt(str::interactive_target_fps_min, v); + return VtValue(v); + } else if (key == str::t_interactive_fps_min) { + float v = 1.0f; + AiRenderGetHintFlt(str::interactive_fps_min, v); + return VtValue(v); + } else if (key == str::t_profile_file) { + return VtValue(std::string(AiProfileGetFileName().c_str())); + } + const auto* nentry = AiNodeGetNodeEntry(_options); + const auto* pentry = AiNodeEntryLookUpParameter(nentry, key.GetText()); + return _GetNodeParamValue(_options, pentry); +} + +// For now we only support a few parameter types, that are expected to have +// UI code in usdview / Maya to Hydra. +HdRenderSettingDescriptorList HdArnoldRenderDelegate::GetRenderSettingDescriptors() const +{ + const auto* nentry = AiNodeGetNodeEntry(_options); + HdRenderSettingDescriptorList ret; + for (const auto& it : _GetSupportedRenderSettings()) { + HdRenderSettingDescriptor desc; + desc.name = it.second.label; + desc.key = it.first; + if (it.second.defaultValue.IsEmpty()) { + const auto* pentry = AiNodeEntryLookUpParameter(nentry, it.first.GetText()); + desc.defaultValue = _GetNodeParamValue(_options, pentry); + } else { + desc.defaultValue = it.second.defaultValue; + } + ret.emplace_back(std::move(desc)); + } + return ret; +} + +HdResourceRegistrySharedPtr HdArnoldRenderDelegate::GetResourceRegistry() const { return _resourceRegistry; } + +HdRenderPassSharedPtr HdArnoldRenderDelegate::CreateRenderPass( + HdRenderIndex* index, const HdRprimCollection& collection) +{ + return HdRenderPassSharedPtr(new HdArnoldRenderPass(this, index, collection)); +} + +HdInstancer* HdArnoldRenderDelegate::CreateInstancer( + HdSceneDelegate* delegate, const SdfPath& id, const SdfPath& instancerId) +{ + return new HdArnoldInstancer(this, delegate, id, instancerId); +} + +void HdArnoldRenderDelegate::DestroyInstancer(HdInstancer* instancer) { delete instancer; } + +HdRprim* HdArnoldRenderDelegate::CreateRprim(const TfToken& typeId, const SdfPath& rprimId, const SdfPath& instancerId) +{ + _renderParam->End(); + if (typeId == HdPrimTypeTokens->mesh) { + return new HdArnoldMesh(this, rprimId, instancerId); + } + if (typeId == HdPrimTypeTokens->volume) { + return new HdArnoldVolume(this, rprimId, instancerId); + } + if (typeId == HdPrimTypeTokens->points) { + return new HdArnoldPoints(this, rprimId, instancerId); + } + TF_CODING_ERROR("Unknown Rprim Type %s", typeId.GetText()); + return nullptr; +} + +void HdArnoldRenderDelegate::DestroyRprim(HdRprim* rPrim) +{ + _renderParam->End(); + delete rPrim; +} + +HdSprim* HdArnoldRenderDelegate::CreateSprim(const TfToken& typeId, const SdfPath& sprimId) +{ + _renderParam->End(); + if (typeId == HdPrimTypeTokens->camera) { + return new HdCamera(sprimId); + } + if (typeId == HdPrimTypeTokens->material) { + return new HdArnoldMaterial(this, sprimId); + } + if (typeId == HdPrimTypeTokens->sphereLight) { + return HdArnoldLight::CreatePointLight(this, sprimId); + } + if (typeId == HdPrimTypeTokens->distantLight) { + return HdArnoldLight::CreateDistantLight(this, sprimId); + } + if (typeId == HdPrimTypeTokens->diskLight) { + return HdArnoldLight::CreateDiskLight(this, sprimId); + } + if (typeId == HdPrimTypeTokens->rectLight) { + return HdArnoldLight::CreateRectLight(this, sprimId); + } + if (typeId == HdPrimTypeTokens->cylinderLight) { + return HdArnoldLight::CreateCylinderLight(this, sprimId); + } + if (typeId == HdPrimTypeTokens->domeLight) { + return HdArnoldLight::CreateDomeLight(this, sprimId); + } + if (typeId == HdPrimTypeTokens->simpleLight) { + // return HdArnoldLight::CreateSimpleLight(this, sprimId); + return nullptr; + } + TF_CODING_ERROR("Unknown Sprim Type %s", typeId.GetText()); + return nullptr; +} + +HdSprim* HdArnoldRenderDelegate::CreateFallbackSprim(const TfToken& typeId) +{ + if (typeId == HdPrimTypeTokens->camera) { + return new HdCamera(SdfPath::EmptyPath()); + } + if (typeId == HdPrimTypeTokens->material) { + return new HdArnoldMaterial(this, SdfPath::EmptyPath()); + } + if (typeId == HdPrimTypeTokens->sphereLight) { + return HdArnoldLight::CreatePointLight(this, SdfPath::EmptyPath()); + } + if (typeId == HdPrimTypeTokens->distantLight) { + return HdArnoldLight::CreateDistantLight(this, SdfPath::EmptyPath()); + } + if (typeId == HdPrimTypeTokens->diskLight) { + return HdArnoldLight::CreateDiskLight(this, SdfPath::EmptyPath()); + } + if (typeId == HdPrimTypeTokens->rectLight) { + return HdArnoldLight::CreateRectLight(this, SdfPath::EmptyPath()); + } + if (typeId == HdPrimTypeTokens->cylinderLight) { + return HdArnoldLight::CreateCylinderLight(this, SdfPath::EmptyPath()); + } + if (typeId == HdPrimTypeTokens->domeLight) { + return HdArnoldLight::CreateDomeLight(this, SdfPath::EmptyPath()); + } + if (typeId == HdPrimTypeTokens->simpleLight) { + // return HdArnoldLight::CreateSimpleLight(this, SdfPath::EmptyPath()); + return nullptr; + } + TF_CODING_ERROR("Unknown Sprim Type %s", typeId.GetText()); + return nullptr; +} + +void HdArnoldRenderDelegate::DestroySprim(HdSprim* sPrim) +{ + _renderParam->End(); + delete sPrim; +} + +HdBprim* HdArnoldRenderDelegate::CreateBprim(const TfToken& typeId, const SdfPath& bprimId) +{ + if (typeId == HdPrimTypeTokens->renderBuffer) { + return new HdArnoldRenderBuffer(bprimId); + } + if (typeId == _tokens->openvdbAsset) { + return new HdArnoldOpenvdbAsset(this, bprimId); + } + TF_CODING_ERROR("Unknown Bprim Type %s", typeId.GetText()); + return nullptr; +} + +HdBprim* HdArnoldRenderDelegate::CreateFallbackBprim(const TfToken& typeId) +{ + if (typeId == HdPrimTypeTokens->renderBuffer) { + return new HdArnoldRenderBuffer(SdfPath()); + } + if (typeId == _tokens->openvdbAsset) { + return new HdArnoldOpenvdbAsset(this, SdfPath()); + } + TF_CODING_ERROR("Unknown Bprim Type %s", typeId.GetText()); + return nullptr; +} + +void HdArnoldRenderDelegate::DestroyBprim(HdBprim* bPrim) { delete bPrim; } + +TfToken HdArnoldRenderDelegate::GetMaterialBindingPurpose() const { return HdTokens->full; } + +TfToken HdArnoldRenderDelegate::GetMaterialNetworkSelector() const { return _tokens->arnold; } + +AtString HdArnoldRenderDelegate::GetLocalNodeName(const AtString& name) const +{ + return AtString(_id.AppendChild(TfToken(name.c_str())).GetText()); +} + +AtUniverse* HdArnoldRenderDelegate::GetUniverse() const { return _universe; } + +AtNode* HdArnoldRenderDelegate::GetOptions() const { return _options; } + +AtNode* HdArnoldRenderDelegate::GetFallbackShader() const { return _fallbackShader; } + +AtNode* HdArnoldRenderDelegate::GetFallbackVolumeShader() const { return _fallbackVolumeShader; } + +HdAovDescriptor HdArnoldRenderDelegate::GetDefaultAovDescriptor(TfToken const& name) const +{ + if (name == HdAovTokens->color) { + return HdAovDescriptor(HdFormatUNorm8Vec4, false, VtValue(GfVec4f(0.0f))); + } else if (name == HdAovTokens->depth) { + return HdAovDescriptor(HdFormatFloat32, false, VtValue(1.0f)); + } else if (name == HdAovTokens->primId) { + return HdAovDescriptor(HdFormatInt32, false, VtValue(-1)); + } + + return HdAovDescriptor(); +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/render_delegate.h b/render_delegate/render_delegate.h new file mode 100755 index 0000000000..608283bfb4 --- /dev/null +++ b/render_delegate/render_delegate.h @@ -0,0 +1,267 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/// @file render_delegate.h +/// +/// Render Delegate class for Hydra. +#pragma once + +#include +#include "api.h" + +#include +#include +#include + +#include "hdarnold.h" +#include "render_param.h" + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +/// Main class point for the Arnold Render Delegate. +class HdArnoldRenderDelegate final : public HdRenderDelegate { +public: + HDARNOLD_API + HdArnoldRenderDelegate(); ///< Constructor for the Render Delegate. + HDARNOLD_API + ~HdArnoldRenderDelegate() override; ///< Destuctor for the Render Delegate. + /// Returns an instance of HdArnoldRenderParam. + /// + /// @return Pointer to an instance of HdArnoldRenderParam. + HDARNOLD_API + HdRenderParam* GetRenderParam() const override; + /// Returns the list of RPrim type names that the Render Delegate supports. + /// + /// This list contains renderable primitive types, like meshes, curves, + /// volumes and so on. + /// + /// @return VtArray holding the name of the supported RPrim types. + HDARNOLD_API + const TfTokenVector& GetSupportedRprimTypes() const override; + /// Returns the list of SPrim type names that the Render Delegate supports. + /// + /// This list contains state primitive types, like cameras, materials and + /// lights. + /// + /// @return VtArray holding the name of the supported SPrim types. + HDARNOLD_API + const TfTokenVector& GetSupportedSprimTypes() const override; + /// Returns the list of BPrim type names that the Render Delegate supports. + /// + /// This list contains buffer primitive types, like render buffers, + /// openvdb assets and so on. + /// + /// @return VtArray holding the name of the supported BPrim types. + HDARNOLD_API + const TfTokenVector& GetSupportedBprimTypes() const override; + /// Sets the Render Setting for the given key. + /// + /// @param key Name of the Render Setting to set. + /// @param value Value of the Render Setting. + HDARNOLD_API + void SetRenderSetting(const TfToken& key, const VtValue& value) override; + /// Gets the Render Setting for the given key. + /// + /// @param key Name of the Render Setting to get. + /// @return Value of the Render Setting. + HDARNOLD_API + VtValue GetRenderSetting(const TfToken& key) const override; + /// Gets the list of Render Setting descriptors. + /// + /// @return std::vector holding HdRenderSettingDescriptor for all the + /// possible Render Settings. + HDARNOLD_API + HdRenderSettingDescriptorList GetRenderSettingDescriptors() const override; + /// Gets the Resource Registry. + /// + /// @return Pointer to the shared HdResourceRegistry. + HDARNOLD_API + HdResourceRegistrySharedPtr GetResourceRegistry() const override; + /// Creates a new Render Pass. + /// + /// @param index Pointer to HdRenderIndex. + /// @param collection RPrim collection to bind to the newly created Render + /// Pass. + /// @return A shared pointer to the new Render Pass or nullptr on error. + HDARNOLD_API + HdRenderPassSharedPtr CreateRenderPass(HdRenderIndex* index, HdRprimCollection const& collection) override; + /// Creates a new Point Instancer. + /// + /// @param delegate Pointer to the Scene Delegate. + /// @param id Path to the Point Instancer. + /// @param instancerId Path to the parent Point Instancer. + /// @return Pointer to a new Point Instancer or nullptr on error. + HDARNOLD_API + HdInstancer* CreateInstancer(HdSceneDelegate* delegate, SdfPath const& id, SdfPath const& instancerId) override; + /// Destroys a Point Instancer. + /// + /// @param instancer Pointer to an instance of HdInstancer. + HDARNOLD_API + void DestroyInstancer(HdInstancer* instancer) override; + /// Creates a new RPrim. + /// + /// @param typeId Type name of the primitive. + /// @param rprimId Path to the primitive. + /// @param instancerId Path to the parent Point Instancer. + /// @return Pointer to the newly created RPrim or nullptr on error. + HDARNOLD_API + HdRprim* CreateRprim(TfToken const& typeId, SdfPath const& rprimId, SdfPath const& instancerId) override; + /// Destroys an RPrim. + /// + /// @param rPrim Pointer to an RPrim. + HDARNOLD_API + void DestroyRprim(HdRprim* rPrim) override; + /// Creates a new SPrim. + /// + /// @param typeId Type of the SPrim to create. + /// @param sprimId Path to the primitive. + /// @return Pointer to a new SPrim or nullptr on error. + HDARNOLD_API + HdSprim* CreateSprim(TfToken const& typeId, SdfPath const& sprimId) override; + /// Creates a fallback SPrim. + /// + /// @param typeId Type of the fallback SPrim to create. + /// @return Pointer to a fallback SPrim or nullptr on error. + HDARNOLD_API + HdSprim* CreateFallbackSprim(TfToken const& typeId) override; + /// Destroys an SPrim. + /// + /// @param sPrim Pointer to an SPrim. + HDARNOLD_API + void DestroySprim(HdSprim* sPrim) override; + /// Creates a new BPrim. + /// + /// @param typeId Type of the new BPrim to create. + /// @param bprimId Path to the primitive. + /// @return Pointer to the newly created BPrim or nullptr on error. + HDARNOLD_API + HdBprim* CreateBprim(TfToken const& typeId, SdfPath const& bprimId) override; + /// Creates a fallback BPrim. + /// + /// @param typeId Type of the fallback Bprim to create. + /// @return Pointer to the fallback BPrim or nullptr on error. + HDARNOLD_API + HdBprim* CreateFallbackBprim(TfToken const& typeId) override; + /// Destroys a BPrim. + /// + /// @param bPrim Pointer to the BPrim. + HDARNOLD_API + void DestroyBprim(HdBprim* bPrim) override; + /// Commits resources to the Render Delegate. + /// + /// This is a callback for a Render Delegate to move, update memory for + /// resources. It currently does nothing, as Arnold handles resource updates + /// during renders. + /// + /// @param tracker Pointer to the Change Tracker. + HDARNOLD_API + void CommitResources(HdChangeTracker* tracker) override; + /// Returns a token to indicate wich material binding should be used. + /// + /// The function currently returns "full", to indicate production renders, + /// not the default "preview" value. + /// + /// @return Name of the preferred material binding. + HDARNOLD_API + TfToken GetMaterialBindingPurpose() const override; + /// Returns a token to indicate which material network should be preferred. + /// + /// The function currently returns "arnold", to indicate using + /// outputs:arnold:surface over outputs:surface (and displacement/volume) + /// if avialable. + /// + /// @return Name of the preferred material network. + HDARNOLD_API + TfToken GetMaterialNetworkSelector() const; + /// Suffixes Node names with the Render Delegate's paths. + /// + /// @param name Name of the Node. + /// @return The Node's name suffixed by the Render Delegate's path. + HDARNOLD_API + AtString GetLocalNodeName(const AtString& name) const; + /// Gets the active Arnold Universe. + /// + /// @return Pointer to the Arnold Universe used by the Render Delegate. + HDARNOLD_API + AtUniverse* GetUniverse() const; + /// Gets the Arnold Options node. + /// + /// @return Pointer to the Arnold Options Node. + HDARNOLD_API + AtNode* GetOptions() const; + /// Gets the fallback Arnold Shader. + /// + /// The fallback shader is a "utility" shader, with "shade_mode" of "flat", + /// "color_mode" of "color" and a "user_data_rgba" is connected to "color", + /// which reads the "color" attribute with the default value of + /// AtRGBA(1.0f, 1.0f, 1.0f, 1.0). + /// + /// @return Pointer to the fallback Arnold Shader. + HDARNOLD_API + AtNode* GetFallbackShader() const; + /// Gets fallback Arnold Volume shader. + /// + /// The fallback shader is just an instances of standard_volume. + /// + /// @return Pointer to the fallback Arnold Volume Shader. + HDARNOLD_API + AtNode* GetFallbackVolumeShader() const; + /// Gets the default settings for supported aovs. + HDARNOLD_API + HdAovDescriptor GetDefaultAovDescriptor(TfToken const& name) const override; + +private: + HdArnoldRenderDelegate(const HdArnoldRenderDelegate&) = delete; + HdArnoldRenderDelegate& operator=(const HdArnoldRenderDelegate&) = delete; + + void _SetRenderSetting(const TfToken& key, const VtValue& value); + + /// Mutex for the shared Resource Registry. + static std::mutex _mutexResourceRegistry; + /// Atomic counter for the shared Resource Registry. + static std::atomic_int _counterResourceRegistry; + /// Pointer to the shared Resource Registry. + static HdResourceRegistrySharedPtr _resourceRegistry; + + /// Pointer to an instance of HdArnoldRenderParam. + /// + /// This is shared with all the primitives, so they can control the flow of + /// rendering. + std::unique_ptr _renderParam; + SdfPath _id; ///< Path of the Render Delegate. + AtUniverse* _universe; ///< Universe used by the Render Delegate. + AtNode* _options; ///< Pointer to the Arnold Options Node. + AtNode* _fallbackShader; ///< Pointer to the fallback Arnold Shader. + AtNode* _fallbackVolumeShader; ///< Pointer to the fallback Arnold Volume Shader. + std::string _logFile; + int _verbosityLogFlags = AI_LOG_WARNINGS | AI_LOG_ERRORS; + bool _ignoreVerbosityLogFlags = false; +}; + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/render_param.cpp b/render_delegate/render_param.cpp new file mode 100755 index 0000000000..697e636662 --- /dev/null +++ b/render_delegate/render_param.cpp @@ -0,0 +1,78 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "render_param.h" + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +bool HdArnoldRenderParam::Render() +{ + const auto status = AiRenderGetStatus(); + if (status == AI_RENDER_STATUS_NOT_STARTED) { + AiRenderBegin(); + return false; + } + if (status == AI_RENDER_STATUS_PAUSED) { + AiRenderRestart(); + return false; + } + if (status == AI_RENDER_STATUS_FINISHED) { + return true; + } + if (status == AI_RENDER_STATUS_RESTARTING) { + return false; + } + AiRenderBegin(); + return false; +} + +void HdArnoldRenderParam::Restart() +{ + const auto status = AiRenderGetStatus(); + if (status != AI_RENDER_STATUS_NOT_STARTED) { + if (status == AI_RENDER_STATUS_RENDERING) { + AiRenderInterrupt(AI_BLOCKING); + } else if (status == AI_RENDER_STATUS_FINISHED) { + AiRenderRestart(); + } + } +} + +void HdArnoldRenderParam::End() +{ + const auto status = AiRenderGetStatus(); + if (status != AI_RENDER_STATUS_NOT_STARTED) { + if (status == AI_RENDER_STATUS_RENDERING || status == AI_RENDER_STATUS_RESTARTING) { + AiRenderAbort(AI_BLOCKING); + } + AiRenderEnd(); + } +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/render_param.h b/render_delegate/render_param.h new file mode 100755 index 0000000000..2dde9d7ee0 --- /dev/null +++ b/render_delegate/render_param.h @@ -0,0 +1,68 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/// @file render_param.h +/// +/// Utilities to control the flow of rendering. +#pragma once + +#include "api.h" + +#include + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +/// Utility class to control the flow of rendering. +class HdArnoldRenderParam final : public HdRenderParam { +public: + /// Constructor for HdArnoldRenderParam. + ~HdArnoldRenderParam() override = default; + + /// Starts or continues rendering. + /// + /// Function to start rendering or resume rendering if it has ended. Returns + /// true if the render finished, false otherwise. + /// + /// @return True if Arnold Core has finished converging. + HDARNOLD_API + bool Render(); + /// Restarts rendering if it's already running or finished. + /// + /// Restarts rendering if the render is already running or finished. Useful + /// when the camera or the rendering resultion changes. + HDARNOLD_API + void Restart(); + /// Ends an ongoing render. + /// + /// Useful when any of the primitives want to make changes. + HDARNOLD_API + void End(); +}; + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/render_pass.cpp b/render_delegate/render_pass.cpp new file mode 100755 index 0000000000..987b78932a --- /dev/null +++ b/render_delegate/render_pass.cpp @@ -0,0 +1,207 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/* + * TODO: + * - Writing to the render buffers directly. + */ +#include "render_pass.h" + +#include + +#include +#include // memset + +#include "config.h" +#include "constant_strings.h" +#include "nodes/nodes.h" +#include "render_buffer.h" +#include "utils.h" + +PXR_NAMESPACE_OPEN_SCOPE + +HdArnoldRenderPass::HdArnoldRenderPass( + HdArnoldRenderDelegate* delegate, HdRenderIndex* index, const HdRprimCollection& collection) + : HdRenderPass(index, collection), _delegate(delegate) +{ + auto* universe = _delegate->GetUniverse(); + _camera = AiNode(universe, str::persp_camera); + AiNodeSetPtr(AiUniverseGetOptions(universe), str::camera, _camera); + AiNodeSetStr(_camera, str::name, _delegate->GetLocalNodeName(str::renderPassCamera)); + _beautyFilter = AiNode(universe, str::gaussian_filter); + AiNodeSetStr(_beautyFilter, str::name, _delegate->GetLocalNodeName(str::renderPassFilter)); + _closestFilter = AiNode(universe, str::closest_filter); + AiNodeSetStr(_closestFilter, str::name, _delegate->GetLocalNodeName(str::renderPassClosestFilter)); + _driver = AiNode(universe, HdArnoldNodeNames::driver); + AiNodeSetStr(_driver, str::name, _delegate->GetLocalNodeName(str::renderPassDriver)); + auto* options = _delegate->GetOptions(); + auto* outputsArray = AiArrayAllocate(3, 1, AI_TYPE_STRING); + const auto beautyString = TfStringPrintf("RGBA RGBA %s %s", AiNodeGetName(_beautyFilter), AiNodeGetName(_driver)); + // We need NDC, and the easiest way is to use the position. + const auto positionString = TfStringPrintf("P VECTOR %s %s", AiNodeGetName(_closestFilter), AiNodeGetName(_driver)); + const auto idString = TfStringPrintf("ID UINT %s %s", AiNodeGetName(_closestFilter), AiNodeGetName(_driver)); + AiArraySetStr(outputsArray, 0, beautyString.c_str()); + AiArraySetStr(outputsArray, 1, positionString.c_str()); + AiArraySetStr(outputsArray, 2, idString.c_str()); + AiNodeSetArray(options, str::outputs, outputsArray); + + const auto& config = HdArnoldConfig::GetInstance(); + AiNodeSetFlt(_camera, str::shutter_start, config.shutter_start); + AiNodeSetFlt(_camera, str::shutter_end, config.shutter_end); +} + +HdArnoldRenderPass::~HdArnoldRenderPass() +{ + AiNodeDestroy(_camera); + AiNodeDestroy(_beautyFilter); + AiNodeDestroy(_closestFilter); + AiNodeDestroy(_driver); +} + +void HdArnoldRenderPass::_Execute(const HdRenderPassStateSharedPtr& renderPassState, const TfTokenVector& renderTags) +{ + TF_UNUSED(renderTags); + auto* renderParam = reinterpret_cast(_delegate->GetRenderParam()); + const auto vp = renderPassState->GetViewport(); + + const auto projMtx = renderPassState->GetProjectionMatrix(); + const auto viewMtx = renderPassState->GetWorldToViewMatrix(); + auto restarted = false; + if (projMtx != _projMtx || viewMtx != _viewMtx) { + _projMtx = projMtx; + _viewMtx = viewMtx; + renderParam->Restart(); + restarted = true; + AiNodeSetMatrix(_camera, str::matrix, HdArnoldConvertMatrix(_viewMtx.GetInverse())); + AiNodeSetMatrix(_driver, HdArnoldDriver::projMtx, HdArnoldConvertMatrix(_projMtx)); + AiNodeSetMatrix(_driver, HdArnoldDriver::viewMtx, HdArnoldConvertMatrix(_viewMtx)); + const auto fov = static_cast(GfRadiansToDegrees(atan(1.0 / _projMtx[0][0]) * 2.0)); + AiNodeSetFlt(_camera, str::fov, fov); + } + + const auto width = static_cast(vp[2]); + const auto height = static_cast(vp[3]); + const auto numPixels = static_cast(width * height); + if (width != _width || height != _height) { + if (!restarted) { + renderParam->Restart(); + } + hdArnoldEmptyBucketQueue([](const HdArnoldBucketData*) {}); + const auto oldNumPixels = static_cast(_width * _height); + _width = width; + _height = height; + + auto* options = _delegate->GetOptions(); + AiNodeSetInt(options, str::xres, _width); + AiNodeSetInt(options, str::yres, _height); + + if (oldNumPixels < numPixels) { + _colorBuffer.resize(numPixels, AtRGBA8()); + _depthBuffer.resize(numPixels, 1.0f); + _primIdBuffer.resize(numPixels, -1); + memset(_colorBuffer.data(), 0, oldNumPixels * sizeof(AtRGBA8)); + std::fill(_depthBuffer.begin(), _depthBuffer.begin() + oldNumPixels, 1.0f); + std::fill(_primIdBuffer.begin(), _primIdBuffer.begin() + oldNumPixels, -1); + } else { + if (numPixels != oldNumPixels) { + _colorBuffer.resize(numPixels); + _depthBuffer.resize(numPixels); + _primIdBuffer.resize(numPixels); + } + memset(_colorBuffer.data(), 0, numPixels * sizeof(AtRGBA8)); + std::fill(_depthBuffer.begin(), _depthBuffer.end(), 1.0f); + std::fill(_primIdBuffer.begin(), _primIdBuffer.end(), -1); + } + } + + _isConverged = renderParam->Render(); + bool needsUpdate = false; + hdArnoldEmptyBucketQueue([this, &needsUpdate](const HdArnoldBucketData* data) { + const auto xo = AiClamp(data->xo, 0, _width - 1); + const auto xe = AiClamp(data->xo + data->sizeX, 0, _width - 1); + if (xe == xo) { + return; + } + const auto yo = AiClamp(data->yo, 0, _height - 1); + const auto ye = AiClamp(data->yo + data->sizeY, 0, _height - 1); + if (ye == yo) { + return; + } + needsUpdate = true; + const auto beautyWidth = (xe - xo) * sizeof(AtRGBA8); + const auto depthWidth = (xe - xo) * sizeof(float); + const auto inOffsetG = xo - data->xo - data->sizeX * data->yo; + const auto outOffsetG = _width * (_height - 1); + for (auto y = yo; y < ye; ++y) { + const auto inOffset = data->sizeX * y + inOffsetG; + const auto outOffset = xo + outOffsetG - _width * y; + memcpy(_colorBuffer.data() + outOffset, data->beauty.data() + inOffset, beautyWidth); + memcpy(_depthBuffer.data() + outOffset, data->depth.data() + inOffset, depthWidth); + memcpy(_primIdBuffer.data() + outOffset, data->primId.data() + inOffset, depthWidth); + } + }); + + HdRenderPassAovBindingVector aovBindings = renderPassState->GetAovBindings(); + + // If the buffers are empty, needsUpdate will be false. + if (aovBindings.empty()) { + // No AOV bindings means blit current framebuffer contents. + if (needsUpdate) { +#ifdef USD_HAS_UPDATED_COMPOSITOR + _compositor.UpdateColor(_width, _height, HdFormat::HdFormatUNorm8Vec4, _colorBuffer.data()); +#else + _compositor.UpdateColor(_width, _height, reinterpret_cast(_colorBuffer.data())); +#endif + _compositor.UpdateDepth(_width, _height, reinterpret_cast(_depthBuffer.data())); + } + _compositor.Draw(); + } else { + // Blit from the framebuffer to the currently selected AOVs. + for (auto& aov : aovBindings) { + if (!TF_VERIFY(aov.renderBuffer != nullptr)) { + continue; + } + + auto* rb = static_cast(aov.renderBuffer); + // Forward convergence state to the render buffers... + rb->SetConverged(_isConverged); + + if (needsUpdate) { + if (aov.aovName == HdAovTokens->color) { + rb->Blit( + HdFormatUNorm8Vec4, width, height, 0, width, reinterpret_cast(_colorBuffer.data())); + } else if (aov.aovName == HdAovTokens->depth) { + rb->Blit(HdFormatFloat32, width, height, 0, width, reinterpret_cast(_depthBuffer.data())); + } else if (aov.aovName == HdAovTokens->primId) { + rb->Blit(HdFormatInt32, width, height, 0, width, reinterpret_cast(_primIdBuffer.data())); + } + } + } + } +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/render_pass.h b/render_delegate/render_pass.h new file mode 100755 index 0000000000..1eb9f73085 --- /dev/null +++ b/render_delegate/render_pass.h @@ -0,0 +1,97 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/// @file render_pass.h +/// +/// Utilities for handling Render Passes. +#pragma once + +#include +#include "api.h" + +#include +#include +#include + +#include "nodes/nodes.h" +#include "render_delegate.h" + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +/// Utility class for handling Render Passes. +class HdArnoldRenderPass : public HdRenderPass { +public: + /// Constructor for HdArnoldRenderPass. + /// + /// @param delegate Pointer to the Render Delegate. + /// @param index Pointer to the Render Index. + /// @param collection RPrim Collection to bind for rendering. + HDARNOLD_API + HdArnoldRenderPass(HdArnoldRenderDelegate* delegate, HdRenderIndex* index, const HdRprimCollection& collection); + /// Destructor for HdArnoldRenderPass. + HDARNOLD_API + ~HdArnoldRenderPass() override; + + /// Returns true if the render has converged. + /// + /// @return True if the render has converged. + bool IsConverged() const { return _isConverged; } + +protected: + /// Executing the Render Pass. + /// + /// This function is continously executed, until IsConverged returns true. + /// + /// @param renderPassState Pointer to the Hydra Render Pass State. + /// @param renderTags List of tags to render, currently unused. + HDARNOLD_API + void _Execute(const HdRenderPassStateSharedPtr& renderPassState, const TfTokenVector& renderTags) override; + +private: + std::vector _colorBuffer; ///< Memory to store the beauty. + std::vector _depthBuffer; ///< Memory to store the depth. + std::vector _primIdBuffer; ///< Memory to store the primId. + HdArnoldRenderDelegate* _delegate; ///< Pointer to the Render Delegate. + AtNode* _camera = nullptr; ///< Pointer to the Arnold Camera. + AtNode* _beautyFilter = nullptr; ///< Pointer to the beauty Arnold Filter. + AtNode* _closestFilter = nullptr; ///< Pointer to the closest Arnold Filter. + AtNode* _driver = nullptr; ///< Pointer to the Arnold Driver. + + HdxCompositor _compositor; ///< Hydra compositor to blit to OpenGL. + + GfMatrix4d _viewMtx; ///< View matrix of the camera. + GfMatrix4d _projMtx; ///< Projection matrix of the camera. + + int _width = 0; ///< Width of the render buffer. + int _height = 0; ///< Height of the render buffer. + + bool _isConverged = false; ///< State of the render convergence. +}; + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/renderer_plugin.cpp b/render_delegate/renderer_plugin.cpp new file mode 100755 index 0000000000..c8a85e38d4 --- /dev/null +++ b/render_delegate/renderer_plugin.cpp @@ -0,0 +1,54 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "renderer_plugin.h" + +#ifdef USD_HAS_NEW_RENDERER_PLUGIN +#include +#else +#include +#endif + +#include "render_delegate.h" + +PXR_NAMESPACE_OPEN_SCOPE + +// Register the Ai plugin with the renderer plugin system. +#ifdef USD_HAS_NEW_RENDERER_PLUGIN + +TF_REGISTRY_FUNCTION(TfType) { HdRendererPluginRegistry::Define(); } +#else +TF_REGISTRY_FUNCTION(TfType) { HdxRendererPluginRegistry::Define(); } +#endif + +HdRenderDelegate* HdArnoldRendererPlugin::CreateRenderDelegate() { return new HdArnoldRenderDelegate(); } + +void HdArnoldRendererPlugin::DeleteRenderDelegate(HdRenderDelegate* renderDelegate) { delete renderDelegate; } + +bool HdArnoldRendererPlugin::IsSupported() const { return true; } + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/renderer_plugin.h b/render_delegate/renderer_plugin.h new file mode 100755 index 0000000000..2f5232c983 --- /dev/null +++ b/render_delegate/renderer_plugin.h @@ -0,0 +1,79 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include +#include "api.h" + +#include "hdarnold.h" + +#ifdef USD_HAS_NEW_RENDERER_PLUGIN +#include +#else +#include +#endif + +PXR_NAMESPACE_OPEN_SCOPE + +#ifdef USD_HAS_NEW_RENDERER_PLUGIN +class HdArnoldRendererPlugin final : public HdRendererPlugin { +#else +class HdArnoldRendererPlugin final : public HdxRendererPlugin { +#endif +public: + /// Default constructor for HdArnoldRendererPlugin. + HDARNOLD_API + HdArnoldRendererPlugin() = default; + /// Default destructor for HdArnoldRendererPlugin. + HDARNOLD_API + ~HdArnoldRendererPlugin() override = default; + + /// This class does not support copying. + HdArnoldRendererPlugin(const HdArnoldRendererPlugin&) = delete; + /// This class does not support copying. + HdArnoldRendererPlugin& operator=(const HdArnoldRendererPlugin&) = delete; + + /// Creates a new Arnold Render Delegate. + /// + /// @return Pointer to the newly created Arnold Render Delegate. + HDARNOLD_API + HdRenderDelegate* CreateRenderDelegate() override; + /// Deletes an Arnold Render Delegate. + /// + /// @param renderDelegate Pointer to the Arnold Render Delegate to delete. + HDARNOLD_API + void DeleteRenderDelegate(HdRenderDelegate* renderDelegate) override; + + /// Returns true if the Render Delegate is supported. + /// + /// @return Value indicating if the Render Delegate is supported. + HDARNOLD_API + bool IsSupported() const override; +}; + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/shape.cpp b/render_delegate/shape.cpp new file mode 100755 index 0000000000..8b2ce7a75f --- /dev/null +++ b/render_delegate/shape.cpp @@ -0,0 +1,91 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "shape.h" + +#include "constant_strings.h" +#include "instancer.h" +#include "utils.h" + +PXR_NAMESPACE_OPEN_SCOPE + +HdArnoldShape::HdArnoldShape( + const AtString& shapeType, HdArnoldRenderDelegate* delegate, const SdfPath& id, const int32_t primId) + : _delegate(delegate) +{ + _shape = AiNode(delegate->GetUniverse(), shapeType); + AiNodeSetStr(_shape, str::name, id.GetText()); + _SetPrimId(primId); +} + +HdArnoldShape::~HdArnoldShape() +{ + AiNodeDestroy(_shape); + for (auto* instance : _instances) { + AiNodeDestroy(instance); + } +} + +void HdArnoldShape::Sync( + HdRprim* rprim, HdDirtyBits dirtyBits, HdSceneDelegate* sceneDelegate, HdArnoldRenderParam* param) +{ + auto& id = rprim->GetId(); + if (HdChangeTracker::IsPrimIdDirty(dirtyBits, id)) { + _SetPrimId(rprim->GetPrimId()); + } + _SyncInstances(dirtyBits, sceneDelegate, param, id, rprim->GetInstancerId()); +} + +void HdArnoldShape::_SetPrimId(int32_t primId) +{ + // Hydra prim IDs are starting from zero, and growing with the number of primitives, so it's safe to directly cast. + // However, prim ID 0 is valid in hydra (the default value for the id buffer in arnold), so we have to to offset + // them by one, so we can use the the 0 prim id to detect background pixels reliably both in CPU and GPU backend + // mode. Later, we'll subtract 1 from the id in the driver. + + AiNodeSetUInt(_shape, str::id, static_cast(primId) + 1); +} + +void HdArnoldShape::_SyncInstances( + HdDirtyBits dirtyBits, HdSceneDelegate* sceneDelegate, HdArnoldRenderParam* param, const SdfPath& id, + const SdfPath& instancerId) +{ + if (instancerId.IsEmpty() || !HdChangeTracker::IsInstanceIndexDirty(dirtyBits, id)) { + return; + } + param->End(); + auto& renderIndex = sceneDelegate->GetRenderIndex(); + auto* instancer = static_cast(renderIndex.GetInstancer(instancerId)); + const auto instanceMatrices = instancer->CalculateInstanceMatrices(id); + const auto oldSize = _instances.size(); + const auto newSize = instanceMatrices.size(); + for (auto i = newSize; i < oldSize; ++i) { + AiNodeDestroy(_instances[i]); + } + + _instances.resize(newSize); + for (auto i = oldSize; i < newSize; ++i) { + auto* instance = AiNode(_delegate->GetUniverse(), str::ginstance); + AiNodeSetPtr(instance, str::node, _shape); + _instances[i] = instance; + std::stringstream ss; + ss << id.GetText() << "_instance_" << i; + AiNodeSetStr(instance, str::name, ss.str().c_str()); + } + + for (auto i = decltype(newSize){0}; i < newSize; ++i) { + AiNodeSetMatrix(_instances[i], str::matrix, HdArnoldConvertMatrix(instanceMatrices[i])); + } +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/shape.h b/render_delegate/shape.h new file mode 100755 index 0000000000..d11ad3a1b1 --- /dev/null +++ b/render_delegate/shape.h @@ -0,0 +1,87 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/// @file shape.h +/// +/// Utilities for handling instanceable Arnold Shapes. +#pragma once + +#include "api.h" + +#include + +#include + +#include + +#include "render_delegate.h" + +PXR_NAMESPACE_OPEN_SCOPE + +class HdRprim; + +/// Utility class for handling instanceable Arnold Shapes. +class HdArnoldShape { +public: + /// Constructor for HdArnoldShape. + /// + /// @param shapeType AtString storing the type of the Arnold Shape node. + /// @param delegate Pointer to the Render Delegate. + /// @param id Path to the primitive. + HDARNOLD_API + HdArnoldShape(const AtString& shapeType, HdArnoldRenderDelegate* delegate, const SdfPath& id, const int32_t primId); + + /// Destructor for HdArnoldShape. + /// + /// Frees the shape and all the ginstances created. + HDARNOLD_API + ~HdArnoldShape(); + + /// Gets the Arnold Shape. + /// + /// @return Pointer to the Arnold Shape. + AtNode* GetShape() { return _shape; } + /// Gets the Arnold Shape. + /// + /// @return Constant pointer to the Arnold Shape. + const AtNode* GetShape() const { return _shape; } + /// Gets the Render Delegate. + /// + /// @return Pointer to the Render Delegate. + HdArnoldRenderDelegate* GetDelegate() { return _delegate; } + /// Syncs internal data and arnold state with hydra. + HDARNOLD_API + void Sync(HdRprim* rprim, HdDirtyBits dirtyBits, HdSceneDelegate* sceneDelegate, HdArnoldRenderParam* param); + +protected: + /// Sets a new hydra-provided primId + void _SetPrimId(int32_t primId); + /// Syncs the Instances. + /// + /// Creates and updates all the instances and destroys the ones not required + /// anymore using the Dirty Bits. + /// + /// @param dirtyBits Dirty Bits to sync. + /// @param sceneDelegate Pointer to the Scene Delegate. + /// @param id Path to the primitive. + /// @param instancerId Path to the Point Instancer. + void _SyncInstances( + HdDirtyBits dirtyBits, HdSceneDelegate* sceneDelegate, HdArnoldRenderParam* param, const SdfPath& id, + const SdfPath& instancerId); + + std::vector _instances; ///< Storing Pointers to the ginstances. + AtNode* _shape; ///< Pointer to the Arnold Shape. + HdArnoldRenderDelegate* _delegate; ///< Pointer to the Render Delegate. +}; + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/utils.cpp b/render_delegate/utils.cpp new file mode 100755 index 0000000000..1b48279e36 --- /dev/null +++ b/render_delegate/utils.cpp @@ -0,0 +1,640 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "utils.h" + +#include + +#include + +#include + +#include "constant_strings.h" + +PXR_NAMESPACE_OPEN_SCOPE + +// clang-format off +TF_DEFINE_PRIVATE_TOKENS(_tokens, + (BOOL) + (BYTE) + (INT) + (UINT) + (FLOAT) + (VECTOR2) + (VECTOR) + (RGB) + (RGBA) + (STRING) + (constant) + (uniform) + (varying) + (indexed) + ((constantArray, "constant ARRAY")) + (displayColor) + ((arnoldPrefix, "arnold:")) + ((visibilityPrefix, "visibility:")) + ((sidednessPrefix, "sidedness:")) + (camera) + (shadow) + (diffuse_transmit) + (specular_transmit) + (volume) + (diffuse_reflect) + (specular_reflect) + (subsurface) +); +// clang-format on + +namespace { + +inline bool _Declare(AtNode* node, const TfToken& name, const TfToken& scope, const TfToken& type) +{ + return AiNodeDeclare(node, name.GetText(), TfStringPrintf("%s %s", scope.GetText(), type.GetText()).c_str()); +} + +template +inline uint32_t _ConvertArray(AtNode* node, const AtString& name, uint8_t arnoldType, const VtValue& value) +{ + if (!value.IsHolding()) { + return 0; + } + const auto& v = value.UncheckedGet(); + auto* arr = AiArrayConvert(v.size(), 1, arnoldType, v.data()); + AiNodeSetArray(node, name, arr); + return AiArrayGetNumElements(arr); +} + +template +inline uint32_t _DeclareAndConvertArray( + AtNode* node, const TfToken& name, const TfToken& scope, const TfToken& type, uint8_t arnoldType, + const VtValue& value) +{ + if (!_Declare(node, name, scope, type)) { + return 0; + } + const auto& v = value.UncheckedGet(); + auto* arr = AiArrayConvert(v.size(), 1, arnoldType, v.data()); + AiNodeSetArray(node, name.GetText(), arr); + return AiArrayGetNumElements(arr); +} + +// This is useful for uniform, vertex and face-varying. We need to know the size +// to generate the indices for faceVarying data. +inline uint32_t _DeclareAndAssignFromArray( + AtNode* node, const TfToken& name, const TfToken& scope, const VtValue& value, bool isColor = false) +{ + if (value.IsHolding()) { + return _DeclareAndConvertArray(node, name, scope, _tokens->BOOL, AI_TYPE_BOOLEAN, value); + } else if (value.IsHolding()) { + return _DeclareAndConvertArray(node, name, scope, _tokens->BYTE, AI_TYPE_BYTE, value); + } else if (value.IsHolding()) { + return _DeclareAndConvertArray(node, name, scope, _tokens->UINT, AI_TYPE_UINT, value); + } else if (value.IsHolding()) { + return _DeclareAndConvertArray(node, name, scope, _tokens->INT, AI_TYPE_INT, value); + } else if (value.IsHolding()) { + return _DeclareAndConvertArray(node, name, scope, _tokens->FLOAT, AI_TYPE_FLOAT, value); + } else if (value.IsHolding()) { + // TODO + } else if (value.IsHolding()) { + return _DeclareAndConvertArray(node, name, scope, _tokens->VECTOR2, AI_TYPE_VECTOR2, value); + } else if (value.IsHolding()) { + if (isColor) { + return _DeclareAndConvertArray(node, name, scope, _tokens->RGB, AI_TYPE_RGB, value); + } else { + return _DeclareAndConvertArray(node, name, scope, _tokens->VECTOR, AI_TYPE_VECTOR, value); + } + } else if (value.IsHolding()) { + return _DeclareAndConvertArray(node, name, scope, _tokens->RGBA, AI_TYPE_RGBA, value); + } + return 0; +} + +inline void _DeclareAndAssignConstant(AtNode* node, const TfToken& name, const VtValue& value, bool isColor = false) +{ + auto declareConstant = [&node, &name](const TfToken& type) -> bool { + return _Declare(node, name, _tokens->constant, type); + }; + if (value.IsHolding()) { + if (!declareConstant(_tokens->BOOL)) { + return; + } + AiNodeSetBool(node, name.GetText(), value.UncheckedGet()); + } else if (value.IsHolding()) { + if (!declareConstant(_tokens->BYTE)) { + return; + } + AiNodeSetByte(node, name.GetText(), value.UncheckedGet()); + } else if (value.IsHolding()) { + if (!declareConstant(_tokens->UINT)) { + return; + } + AiNodeSetUInt(node, name.GetText(), value.UncheckedGet()); + } else if (value.IsHolding()) { + if (!declareConstant(_tokens->INT)) { + return; + } + AiNodeSetInt(node, name.GetText(), value.UncheckedGet()); + } else if (value.IsHolding()) { + if (!declareConstant(_tokens->FLOAT)) { + return; + } + AiNodeSetFlt(node, name.GetText(), value.UncheckedGet()); + } else if (value.IsHolding()) { + if (!declareConstant(_tokens->FLOAT)) { + return; + } + AiNodeSetFlt(node, name.GetText(), static_cast(value.UncheckedGet())); + } else if (value.IsHolding()) { + if (!declareConstant(_tokens->VECTOR2)) { + return; + } + const auto& v = value.UncheckedGet(); + AiNodeSetVec2(node, name.GetText(), v[0], v[1]); + } else if (value.IsHolding()) { + if (isColor) { + if (!declareConstant(_tokens->RGB)) { + return; + } + const auto& v = value.UncheckedGet(); + AiNodeSetRGB(node, name.GetText(), v[0], v[1], v[2]); + } else { + if (!declareConstant(_tokens->VECTOR)) { + return; + } + const auto& v = value.UncheckedGet(); + AiNodeSetVec(node, name.GetText(), v[0], v[1], v[2]); + } + } else if (value.IsHolding()) { + if (!declareConstant(_tokens->RGBA)) { + return; + } + const auto& v = value.UncheckedGet(); + AiNodeSetRGBA(node, name.GetText(), v[0], v[1], v[2], v[3]); + } else { + // Display color is a special case, where an array with a single + // element should be translated to a single, constant RGB. + if (name == _tokens->displayColor && value.IsHolding()) { + const auto& v = value.UncheckedGet(); + if (v.size() == 1) { + if (declareConstant(_tokens->RGB)) { + AiNodeSetRGB(node, name.GetText(), v[0][0], v[0][1], v[0][2]); + return; + } + } + } + _DeclareAndAssignFromArray(node, name, _tokens->constantArray, value, isColor); + } +} + +inline bool _TokenStartsWithToken(const TfToken& t0, const TfToken& t1) +{ + return strncmp(t0.GetText(), t1.GetText(), t1.size()) == 0; +} + +inline bool _CharStartsWithToken(const char* c, const TfToken& t) { return strncmp(c, t.GetText(), t.size()) == 0; } + +inline void _SetRayFlag(AtNode* node, const AtString& paramName, const char* rayName, const VtValue& value) +{ + auto flag = true; + if (value.IsHolding()) { + flag = value.UncheckedGet(); + } else if (value.IsHolding()) { + flag = value.UncheckedGet() != 0; + } else if (value.IsHolding()) { + flag = value.UncheckedGet() != 0; + } else { + // Invalid value stored. + return; + } + uint8_t bitFlag = 0; + if (_CharStartsWithToken(rayName, _tokens->camera)) { + bitFlag = AI_RAY_CAMERA; + } else if (_CharStartsWithToken(rayName, _tokens->shadow)) { + bitFlag = AI_RAY_SHADOW; + } else if (_CharStartsWithToken(rayName, _tokens->diffuse_transmit)) { + bitFlag = AI_RAY_DIFFUSE_TRANSMIT; + } else if (_CharStartsWithToken(rayName, _tokens->specular_transmit)) { + bitFlag = AI_RAY_SPECULAR_TRANSMIT; + } else if (_CharStartsWithToken(rayName, _tokens->volume)) { + bitFlag = AI_RAY_VOLUME; + } else if (_CharStartsWithToken(rayName, _tokens->diffuse_reflect)) { + bitFlag = AI_RAY_DIFFUSE_REFLECT; + } else if (_CharStartsWithToken(rayName, _tokens->specular_reflect)) { + bitFlag = AI_RAY_SPECULAR_REFLECT; + } else if (_CharStartsWithToken(rayName, _tokens->subsurface)) { + bitFlag = AI_RAY_SUBSURFACE; + } + auto currentFlag = AiNodeGetByte(node, paramName); + if (flag) { + currentFlag = currentFlag | bitFlag; + } else { + currentFlag = currentFlag & ~bitFlag; + } + AiNodeSetByte(node, paramName, currentFlag); +} + +} // namespace + +AtMatrix HdArnoldConvertMatrix(const GfMatrix4d& in) +{ + AtMatrix out = AI_M4_IDENTITY; + out.data[0][0] = static_cast(in[0][0]); + out.data[0][1] = static_cast(in[0][1]); + out.data[0][2] = static_cast(in[0][2]); + out.data[0][3] = static_cast(in[0][3]); + out.data[1][0] = static_cast(in[1][0]); + out.data[1][1] = static_cast(in[1][1]); + out.data[1][2] = static_cast(in[1][2]); + out.data[1][3] = static_cast(in[1][3]); + out.data[2][0] = static_cast(in[2][0]); + out.data[2][1] = static_cast(in[2][1]); + out.data[2][2] = static_cast(in[2][2]); + out.data[2][3] = static_cast(in[2][3]); + out.data[3][0] = static_cast(in[3][0]); + out.data[3][1] = static_cast(in[3][1]); + out.data[3][2] = static_cast(in[3][2]); + out.data[3][3] = static_cast(in[3][3]); + return out; +} + +AtMatrix HdArnoldConvertMatrix(const GfMatrix4f& in) +{ + AtMatrix out = AI_M4_IDENTITY; + out.data[0][0] = in[0][0]; + out.data[0][1] = in[0][1]; + out.data[0][2] = in[0][2]; + out.data[0][3] = in[0][3]; + out.data[1][0] = in[1][0]; + out.data[1][1] = in[1][1]; + out.data[1][2] = in[1][2]; + out.data[1][3] = in[1][3]; + out.data[2][0] = in[2][0]; + out.data[2][1] = in[2][1]; + out.data[2][2] = in[2][2]; + out.data[2][3] = in[2][3]; + out.data[3][0] = in[3][0]; + out.data[3][1] = in[3][1]; + out.data[3][2] = in[3][2]; + out.data[3][3] = in[3][3]; + return out; +} + +GfMatrix4f HdArnoldConvertMatrix(const AtMatrix& in) +{ + GfMatrix4f out(1.0f); + out[0][0] = in.data[0][0]; + out[0][1] = in.data[0][1]; + out[0][2] = in.data[0][2]; + out[0][3] = in.data[0][3]; + out[1][0] = in.data[1][0]; + out[1][1] = in.data[1][1]; + out[1][2] = in.data[1][2]; + out[1][3] = in.data[1][3]; + out[2][0] = in.data[2][0]; + out[2][1] = in.data[2][1]; + out[2][2] = in.data[2][2]; + out[2][3] = in.data[2][3]; + out[3][0] = in.data[3][0]; + out[3][1] = in.data[3][1]; + out[3][2] = in.data[3][2]; + out[3][3] = in.data[3][3]; + return out; +} + +void HdArnoldSetTransform(AtNode* node, HdSceneDelegate* delegate, const SdfPath& id) +{ + // For now this is hardcoded to two samples and 0.0 / 1.0 sample times. + constexpr size_t maxSamples = 2; + HdTimeSampleArray xf{}; + delegate->SampleTransform(id, &xf); + AtArray* matrices = AiArrayAllocate(1, xf.count, AI_TYPE_MATRIX); + for (auto i = decltype(xf.count){0}; i < xf.count; ++i) { + AiArraySetMtx(matrices, i, HdArnoldConvertMatrix(xf.values[i])); + } + AiNodeSetArray(node, str::matrix, matrices); +} + +void HdArnoldSetTransform(const std::vector& nodes, HdSceneDelegate* delegate, const SdfPath& id) +{ + constexpr size_t maxSamples = 3; + HdTimeSampleArray xf{}; + delegate->SampleTransform(id, &xf); + AtArray* matrices = AiArrayAllocate(1, xf.count, AI_TYPE_MATRIX); + for (auto i = decltype(xf.count){0}; i < xf.count; ++i) { + AiArraySetMtx(matrices, i, HdArnoldConvertMatrix(xf.values[i])); + } + const auto nodeCount = nodes.size(); + if (nodeCount > 0) { + // You can't set the same array on two different nodes, + // because it causes a double-free. + // TODO(pal): we need to check if it's still the case with Arnold 5. + for (auto i = decltype(nodeCount){1}; i < nodeCount; ++i) { + AiNodeSetArray(nodes[i], str::matrix, AiArrayCopy(matrices)); + } + AiNodeSetArray(nodes[0], str::matrix, matrices); + } +} + +void HdArnoldSetParameter(AtNode* node, const AtParamEntry* pentry, const VtValue& value) +{ + const auto paramName = AiParamGetName(pentry); + const auto paramType = AiParamGetType(pentry); + if (paramType == AI_TYPE_ARRAY) { + auto* defaultParam = AiParamGetDefault(pentry); + if (defaultParam->ARRAY() == nullptr) { + return; + } + const auto arrayType = AiArrayGetType(defaultParam->ARRAY()); + switch (arrayType) { + // TODO(pal): Add support for missing types. + // And convert/test different type conversions. + case AI_TYPE_INT: + case AI_TYPE_ENUM: + _ConvertArray(node, paramName, AI_TYPE_INT, value); + break; + case AI_TYPE_UINT: + _ConvertArray(node, paramName, arrayType, value); + break; + case AI_TYPE_BOOLEAN: + _ConvertArray(node, paramName, arrayType, value); + break; + case AI_TYPE_FLOAT: + case AI_TYPE_HALF: + _ConvertArray(node, paramName, AI_TYPE_FLOAT, value); + break; + case AI_TYPE_VECTOR2: + _ConvertArray(node, paramName, arrayType, value); + break; + case AI_TYPE_RGB: + case AI_TYPE_VECTOR: + _ConvertArray(node, paramName, arrayType, value); + break; + case AI_TYPE_RGBA: + _ConvertArray(node, paramName, arrayType, value); + break; + default: + AiMsgError("Unsupported array parameter %s.%s", AiNodeGetName(node), AiParamGetName(pentry).c_str()); + } + return; + } + switch (paramType) { + case AI_TYPE_BYTE: + if (value.IsHolding()) { + AiNodeSetByte(node, paramName, static_cast(value.UncheckedGet())); + } + break; + case AI_TYPE_INT: + if (value.IsHolding()) { + AiNodeSetInt(node, paramName, value.UncheckedGet()); + } else if (value.IsHolding()) { + AiNodeSetInt(node, paramName, value.UncheckedGet()); + } + break; + case AI_TYPE_UINT: + case AI_TYPE_USHORT: + if (value.IsHolding()) { + AiNodeSetUInt(node, paramName, value.UncheckedGet()); + } + break; + case AI_TYPE_BOOLEAN: + if (value.IsHolding()) { + AiNodeSetBool(node, paramName, value.UncheckedGet()); + } else if (value.IsHolding()) { + AiNodeSetBool(node, paramName, value.UncheckedGet() != 0); + } else if (value.IsHolding()) { + AiNodeSetBool(node, paramName, value.UncheckedGet() != 0); + } + break; + case AI_TYPE_FLOAT: + case AI_TYPE_HALF: + if (value.IsHolding()) { + AiNodeSetFlt(node, paramName, value.UncheckedGet()); + } else if (value.IsHolding()) { + AiNodeSetFlt(node, paramName, static_cast(value.UncheckedGet())); + } + break; + case AI_TYPE_RGB: + if (value.IsHolding()) { + const auto& v = value.UncheckedGet(); + AiNodeSetRGB(node, paramName, v[0], v[1], v[2]); + } + break; + case AI_TYPE_RGBA: + if (value.IsHolding()) { + const auto& v = value.UncheckedGet(); + AiNodeSetRGBA(node, paramName, v[0], v[1], v[2], v[3]); + } + break; + case AI_TYPE_VECTOR: + if (value.IsHolding()) { + const auto& v = value.UncheckedGet(); + AiNodeSetVec(node, paramName, v[0], v[1], v[2]); + } + break; + case AI_TYPE_VECTOR2: + if (value.IsHolding()) { + const auto& v = value.UncheckedGet(); + AiNodeSetVec2(node, paramName, v[0], v[1]); + } + break; + case AI_TYPE_STRING: + if (value.IsHolding()) { + AiNodeSetStr(node, paramName, value.UncheckedGet().GetText()); + } else if (value.IsHolding()) { + const auto& assetPath = value.UncheckedGet(); + AiNodeSetStr( + node, paramName, + assetPath.GetResolvedPath().empty() ? assetPath.GetAssetPath().c_str() + : assetPath.GetResolvedPath().c_str()); + } else if (value.IsHolding()) { + AiNodeSetStr(node, paramName, value.UncheckedGet().c_str()); + } + break; + case AI_TYPE_POINTER: + case AI_TYPE_NODE: + break; // TODO: Should be in the relationships list. + case AI_TYPE_MATRIX: + break; // TODO + case AI_TYPE_ENUM: + if (value.IsHolding()) { + AiNodeSetInt(node, paramName, value.UncheckedGet()); + } else if (value.IsHolding()) { + AiNodeSetInt(node, paramName, value.UncheckedGet()); + } else if (value.IsHolding()) { + AiNodeSetStr(node, paramName, value.UncheckedGet().GetText()); + } else if (value.IsHolding()) { + AiNodeSetStr(node, paramName, value.UncheckedGet().c_str()); + } + break; + case AI_TYPE_CLOSURE: + break; // Should be in the relationships list. + default: + AiMsgError("Unsupported parameter %s.%s", AiNodeGetName(node), AiParamGetName(pentry).c_str()); + } +} + +bool ConvertPrimvarToBuiltinParameter( + AtNode* node, const SdfPath& id, HdSceneDelegate* delegate, const HdPrimvarDescriptor& primvarDesc) +{ + if (!_TokenStartsWithToken(primvarDesc.name, _tokens->arnoldPrefix)) { + return false; + } + + const auto* paramName = primvarDesc.name.GetText() + _tokens->arnoldPrefix.size(); + // We are checking if it's a visibility flag in form of + // primvars:arnold:visibility:xyz where xyz is a name of a ray type. + if (_CharStartsWithToken(paramName, _tokens->visibilityPrefix)) { + const auto* rayName = paramName + _tokens->visibilityPrefix.size(); + _SetRayFlag(node, str::visibility, rayName, delegate->Get(id, primvarDesc.name)); + return true; + } + if (_CharStartsWithToken(paramName, _tokens->sidednessPrefix)) { + const auto* rayName = paramName + _tokens->sidednessPrefix.size(); + _SetRayFlag(node, str::sidedness, rayName, delegate->Get(id, primvarDesc.name)); + return true; + } + const auto* nodeEntry = AiNodeGetNodeEntry(node); + const auto* paramEntry = AiNodeEntryLookUpParameter(nodeEntry, paramName); + if (paramEntry != nullptr) { + HdArnoldSetParameter(node, paramEntry, delegate->Get(id, primvarDesc.name)); + } + return true; +} + +void HdArnoldSetConstantPrimvar( + AtNode* node, const SdfPath& id, HdSceneDelegate* delegate, const HdPrimvarDescriptor& primvarDesc) +{ + // Remap primvars:arnold:xyz parameters to xyz parameters on the node. + if (ConvertPrimvarToBuiltinParameter(node, id, delegate, primvarDesc)) { + return; + } + const auto isColor = primvarDesc.role == HdPrimvarRoleTokens->color; + if (primvarDesc.name == HdPrimvarRoleTokens->color && isColor) { + if (!_Declare(node, primvarDesc.name, _tokens->constant, _tokens->RGBA)) { + return; + } + const auto value = delegate->Get(id, primvarDesc.name); + if (value.IsHolding()) { + const auto& v = value.UncheckedGet(); + AiNodeSetRGBA(node, primvarDesc.name.GetText(), v[0], v[1], v[2], v[3]); + } else if (value.IsHolding()) { + const auto& arr = value.UncheckedGet(); + if (arr.empty()) { + return; + } + const auto& v = arr[0]; + AiNodeSetRGBA(node, primvarDesc.name.GetText(), v[0], v[1], v[2], v[3]); + } + } + _DeclareAndAssignConstant(node, primvarDesc.name, delegate->Get(id, primvarDesc.name), isColor); +} + +void HdArnoldSetUniformPrimvar( + AtNode* node, const SdfPath& id, HdSceneDelegate* delegate, const HdPrimvarDescriptor& primvarDesc) +{ + _DeclareAndAssignFromArray( + node, primvarDesc.name, _tokens->uniform, delegate->Get(id, primvarDesc.name), + primvarDesc.role == HdPrimvarRoleTokens->color); +} + +void HdArnoldSetVertexPrimvar( + AtNode* node, const SdfPath& id, HdSceneDelegate* delegate, const HdPrimvarDescriptor& primvarDesc) +{ + _DeclareAndAssignFromArray( + node, primvarDesc.name, _tokens->varying, delegate->Get(id, primvarDesc.name), + primvarDesc.role == HdPrimvarRoleTokens->color); +} + +void HdArnoldSetFaceVaryingPrimvar( + AtNode* node, const SdfPath& id, HdSceneDelegate* delegate, const HdPrimvarDescriptor& primvarDesc) +{ + const auto numElements = _DeclareAndAssignFromArray( + node, primvarDesc.name, _tokens->indexed, delegate->Get(id, primvarDesc.name), + primvarDesc.role == HdPrimvarRoleTokens->color); + if (numElements != 0) { + auto* a = AiArrayAllocate(numElements, 1, AI_TYPE_UINT); + for (auto i = decltype(numElements){0}; i < numElements; ++i) { + AiArraySetUInt(a, i, i); + } + AiNodeSetArray(node, TfStringPrintf("%sidxs", primvarDesc.name.GetText()).c_str(), a); + } +} + +void HdArnoldSetPositionFromPrimvar( + AtNode* node, const SdfPath& id, HdSceneDelegate* delegate, const AtString& paramName) +{ + constexpr size_t maxSamples = 2; + HdTimeSampleArray xf; + delegate->SamplePrimvar(id, HdTokens->points, &xf); + if (xf.count == 0 && ARCH_UNLIKELY(!xf.values[0].IsHolding())) { + return; + } + const auto& v0 = xf.values[0].Get(); + if (xf.count > 1 && ARCH_UNLIKELY(!xf.values[1].IsHolding())) { + xf.count = 1; + } + auto* arr = AiArrayAllocate(v0.size(), xf.count, AI_TYPE_VECTOR); + AiArraySetKey(arr, 0, v0.data()); + if (xf.count > 1) { + const auto& v1 = xf.values[1].Get(); + if (ARCH_LIKELY(v1.size() == v0.size())) { + AiArraySetKey(arr, 1, v1.data()); + } else { + AiArraySetKey(arr, 1, v0.data()); + } + } + AiNodeSetArray(node, paramName, arr); +} + +void HdArnoldSetRadiusFromPrimvar(AtNode* node, const SdfPath& id, HdSceneDelegate* delegate) +{ + constexpr size_t maxSamples = 2; + HdTimeSampleArray xf; + delegate->SamplePrimvar(id, HdTokens->widths, &xf); + if (xf.count == 0 && ARCH_UNLIKELY(!xf.values[0].IsHolding())) { + return; + } + const auto& v0 = xf.values[0].Get(); + if (xf.count > 1 && ARCH_UNLIKELY(!xf.values[1].IsHolding())) { + xf.count = 1; + } + auto* arr = AiArrayAllocate(v0.size(), xf.count, AI_TYPE_FLOAT); + auto* out = static_cast(AiArrayMapKey(arr, 0)); + std::transform(v0.begin(), v0.end(), out, [](const float w) -> float { return w * 0.5f; }); + if (xf.count > 1) { + out = static_cast(AiArrayMapKey(arr, 1)); + const auto& v1 = xf.values[1].Get(); + if (ARCH_LIKELY(v1.size() == v0.size())) { + std::transform(v1.begin(), v1.end(), out, [](const float w) -> float { return w * 0.5f; }); + } else { + std::transform(v0.begin(), v0.end(), out, [](const float w) -> float { return w * 0.5f; }); + } + } + AiNodeSetArray(node, str::radius, arr); +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/utils.h b/render_delegate/utils.h new file mode 100755 index 0000000000..751b7de9be --- /dev/null +++ b/render_delegate/utils.h @@ -0,0 +1,166 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/// @file utils.h +/// +/// General utilities for Hydra <> Arnold interop. +#pragma once + +#include +#include "api.h" + +#include +#include + +#include + +#include + +#include + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +/// Converts a double precision GfMatrix to AtMatrix. +/// +/// @param in Double Precision GfMatrix. +/// @return AtMatrix converted from the GfMatrix. +HDARNOLD_API +AtMatrix HdArnoldConvertMatrix(const GfMatrix4d& in); +/// Converts a single precision GfMatrix to AtMatrix. +/// +/// @param in Single Precision GfMatrix. +/// @return AtMatrix converted from the GfMatrix. +HDARNOLD_API +AtMatrix HdArnoldConvertMatrix(const GfMatrix4f& in); +/// Converts an AtMatrix to a single precision GfMatrix. +/// +/// @param in AtMatrix. +/// @return GfMatrix converted from the AtMatrix. +HDARNOLD_API +GfMatrix4f HdArnoldConvertMatrix(const AtMatrix& in); +/// Sets the transform on an Arnold node from a Hydra Primitive. +/// +/// @param node Pointer to the Arnold Node. +/// @param delegate Pointer to the Scene Delegate. +/// @param id Path to the primitive. +HDARNOLD_API +void HdArnoldSetTransform(AtNode* node, HdSceneDelegate* delegate, const SdfPath& id); +/// Sets the transform on multiple Arnold nodes from a single Hydra Primitive. +/// +/// @param node Vector holding all the Arnold Nodes. +/// @param delegate Pointer to the Scene Delegate. +/// @param id Path to the primitive. +HDARNOLD_API +void HdArnoldSetTransform(const std::vector& nodes, HdSceneDelegate* delegate, const SdfPath& id); +/// Sets a Parameter on an Arnold Node from a VtValue. +/// +/// @param node Pointer to the Arnold Node. +/// @param pentry Pointer to a Constant AtParamEntry struct for the Parameter. +/// @param value VtValue of the Value to be set. +HDARNOLD_API +void HdArnoldSetParameter(AtNode* node, const AtParamEntry* pentry, const VtValue& value); +/// Converts constant scope primvars to built-in parameters. +/// +/// @param node Pointer to an Arnold node. +/// @param id Path to the Primitive. +/// @param delegate Pointer to the Scene Delegate. +/// @param primvarDesc Primvar Descriptor for the Primvar to be set. +HDARNOLD_API +bool ConvertPrimvarToBuiltinParameter( + AtNode* node, const SdfPath& id, HdSceneDelegate* delegate, const HdPrimvarDescriptor& primvarDesc); +/// Sets a Constant scope Primvar on an Arnold node from a Hydra Primitive. +/// +/// There is some additional type remapping done to deal with various third +/// party apps: +/// bool -> bool / int / long +/// int -> int / long +/// float -> float / double +/// +/// The function also calls ConvertPrimvarToBuiltinParameter. +/// +/// @param node Pointer to an Arnold Node. +/// @param id Path to the Primitive. +/// @param delegate Pointer to the Scene Delegate. +/// @param primvarDesch Primvar Descriptor for the Primvar to be set. +HDARNOLD_API +void HdArnoldSetConstantPrimvar( + AtNode* node, const SdfPath& id, HdSceneDelegate* delegate, const HdPrimvarDescriptor& primvarDesc); +/// Sets a Uniform scope Primvar on an Arnold node from a Hydra Primitive. +/// +/// If the parameter is named arnold:xyz (so it exist in the form of +/// primvars:arnold:xyz), the function checks if a normal parameter exist with +/// the same name as removing the arnold: prefix. +/// +/// @param node Pointer to an Arnold Node. +/// @param id Path to the Primitive. +/// @param delegate Pointer to the Scene Delegate. +/// @param primvarDesch Primvar Descriptor for the Primvar to be set. +HDARNOLD_API +void HdArnoldSetUniformPrimvar( + AtNode* node, const SdfPath& id, HdSceneDelegate* delegate, const HdPrimvarDescriptor& primvarDesc); +/// Sets a Vertex scope Primvar on an Arnold node from a Hydra Primitive. +/// +/// @param node Pointer to an Arnold Node. +/// @param id Path to the Primitive. +/// @param delegate Pointer to the Scene Delegate. +/// @param primvarDesch Primvar Descriptor for the Primvar to be set. +HDARNOLD_API +void HdArnoldSetVertexPrimvar( + AtNode* node, const SdfPath& id, HdSceneDelegate* delegate, const HdPrimvarDescriptor& primvarDesc); +/// Sets a Face-Varying scope Primvar on an Arnold node from a Hydra Primitive. +/// +/// @param node Pointer to an Arnold Node. +/// @param id Path to the Primitive. +/// @param delegate Pointer to the Scene Delegate. +/// @param primvarDesch Primvar Descriptor for the Primvar to be set. +HDARNOLD_API +void HdArnoldSetFaceVaryingPrimvar( + AtNode* node, const SdfPath& id, HdSceneDelegate* delegate, const HdPrimvarDescriptor& primvarDesc); +/// Sets positions attribute on an Arnold shape from a VtVec3fArray primvar. +/// +/// @param node Pointer to an Arnold node. +/// @param paramName Name of the positions parameter on the Arnold node. +/// @param id Path to the Hydra Primitive. +/// @param delegate Pointer to the Scene Delegate. +HDARNOLD_API +void HdArnoldSetPositionFromPrimvar( + AtNode* node, const SdfPath& id, HdSceneDelegate* delegate, const AtString& paramName); +/// Sets radius attribute on an Arnold shape from a float primvar. +/// +/// This function looks for a widths primvar, which will be multiplied by 0.5 +/// before set on the node. +/// +/// @param node Pointer to an Arnold node. +/// @param paramName Name of the positions parameter on the Arnold node. +/// @param id Path to the Hydra Primitive. +/// @param delegate Pointer to the Scene Delegate. +HDARNOLD_API +void HdArnoldSetRadiusFromPrimvar(AtNode* node, const SdfPath& id, HdSceneDelegate* delegate); + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/volume.cpp b/render_delegate/volume.cpp new file mode 100755 index 0000000000..b1cceaa3f7 --- /dev/null +++ b/render_delegate/volume.cpp @@ -0,0 +1,321 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "volume.h" + +#include + +#include + +#include + +#include "constant_strings.h" +#include "material.h" +#include "openvdb_asset.h" +#include "utils.h" + +#ifdef BUILD_HOUDINI_TOOLS +#include +#include +#include +#include + +// These don't seem to be publicly exposed anywhere? +#if defined(ARCH_OS_WINDOWS) +#include +#define GETSYM(handle, name) GetProcAddress((HMODULE)handle, name) +#else +#include +#define WINAPI +#define GETSYM(handle, name) dlsym(handle, name) +#endif +#endif + +PXR_NAMESPACE_OPEN_SCOPE + +namespace { + +#ifdef BUILD_HOUDINI_TOOLS + +using HouGetHoudiniVdbPrimitive = void* (*)(const char*, const char*); +using HouGetHoudiniVolumePrimitive = void* (*)(const char*, const char*, int); +struct HouFnSet { + HouGetHoudiniVdbPrimitive getVdbVolumePrimitive = nullptr; + HouGetHoudiniVolumePrimitive getHoudiniVolumePrimitive = nullptr; + + HouFnSet() + { + constexpr auto getVdbName = "SOPgetVDBVolumePrimitive"; + constexpr auto getHoudiniName = "SOPgetHoudiniVolumePrimitive"; + const auto HFS = ArchGetEnv("HFS"); + const auto dsoPath = HFS + ARCH_PATH_SEP + "houdini" + ARCH_PATH_SEP + "dso" + ARCH_PATH_SEP + "USD_SopVol" + + ARCH_LIBRARY_SUFFIX; + // We don't have to worry about unloading the library, as our library + // will be unloaded before Houdini exits. + auto* sopVol = ArchLibraryOpen(dsoPath, ARCH_LIBRARY_NOW); + if (sopVol == nullptr) { + return; + } + getVdbVolumePrimitive = reinterpret_cast(GETSYM(sopVol, getVdbName)); + getHoudiniVolumePrimitive = reinterpret_cast(GETSYM(sopVol, getHoudiniName)); + } +}; + +const HouFnSet& GetHouFunctionSet() +{ + static HouFnSet ret; + return ret; +} + +using HtoAConvertPrimVdbToArnold = void (*)(void*, int, void**); + +struct HtoAFnSet { + HtoAConvertPrimVdbToArnold convertPrimVdbToArnold = nullptr; + + HtoAFnSet() + { + // The symbol is stored in _htoa_pygeo.so in python2.7libs, and + // htoa is typically configured using HOUDINI_PATH. We should refine + // this method in the future. + constexpr auto convertVdbName = "HtoAConvertPrimVdbToArnold"; + const auto HOUDINI_PATH = ArchGetEnv("HOUDINI_PATH"); + void* htoaPygeo = nullptr; + const auto houdiniPaths = TfStringSplit(HOUDINI_PATH, ARCH_PATH_LIST_SEP); + for (const auto& houdiniPath : houdiniPaths) { + const auto dsoPath = houdiniPath + ARCH_PATH_SEP + "python2.7libs" + ARCH_PATH_SEP + "_htoa_pygeo" + +// HTOA sets this library's extension to .so even on linux. +#ifdef ARCH_OS_WINDOWS + ".dll" +#else + ".so" +#endif + ; + htoaPygeo = ArchLibraryOpen(dsoPath, ARCH_LIBRARY_NOW); + if (htoaPygeo != nullptr) { + break; + } + } + + if (htoaPygeo == nullptr) { + return; + } + + convertPrimVdbToArnold = reinterpret_cast(GETSYM(htoaPygeo, convertVdbName)); + } +}; + +const HtoAFnSet GetHtoAFunctionSet() +{ + static HtoAFnSet ret; + return ret; +} + +#endif + +} // namespace + +// clang-format off +TF_DEFINE_PRIVATE_TOKENS(_tokens, + (openvdbAsset) + (filePath) +); +// clang-format on + +HdArnoldVolume::HdArnoldVolume(HdArnoldRenderDelegate* delegate, const SdfPath& id, const SdfPath& instancerId) + : HdVolume(id, instancerId), _delegate(delegate) +{ +} + +HdArnoldVolume::~HdArnoldVolume() +{ + for (auto* volume : _volumes) { + AiNodeDestroy(volume); + } +#ifdef BUILD_HOUDINI_TOOLS + for (auto* volume : _inMemoryVolumes) { + AiNodeDestroy(volume); + } +#endif +} + +void HdArnoldVolume::Sync( + HdSceneDelegate* delegate, HdRenderParam* renderParam, HdDirtyBits* dirtyBits, const TfToken& reprToken) +{ + TF_UNUSED(reprToken); + auto* param = reinterpret_cast(renderParam); + const auto& id = GetId(); + auto volumesChanged = false; + if (HdChangeTracker::IsTopologyDirty(*dirtyBits, id)) { + param->End(); + _CreateVolumes(id, delegate); + volumesChanged = true; + } + + if (volumesChanged || (*dirtyBits & HdChangeTracker::DirtyMaterialId)) { + param->End(); + const auto* material = reinterpret_cast( + delegate->GetRenderIndex().GetSprim(HdPrimTypeTokens->material, delegate->GetMaterialId(id))); + auto* volumeShader = material != nullptr ? material->GetVolumeShader() : _delegate->GetFallbackVolumeShader(); + for (auto& volume : _volumes) { + AiNodeSetPtr(volume, str::shader, volumeShader); + } +#ifdef BUILD_HOUDINI_TOOLS + for (auto& volume : _inMemoryVolumes) { + AiNodeSetPtr(volume, str::shader, volumeShader); + } +#endif + } + + if (HdChangeTracker::IsTransformDirty(*dirtyBits, id)) { + param->End(); + HdArnoldSetTransform(_volumes, delegate, GetId()); + } + + *dirtyBits = HdChangeTracker::Clean; +} + +void HdArnoldVolume::_CreateVolumes(const SdfPath& id, HdSceneDelegate* delegate) +{ + std::unordered_map> openvdbs; +#ifdef BUILD_HOUDINI_TOOLS + std::unordered_map> houVdbs; +#endif + const auto fieldDescriptors = delegate->GetVolumeFieldDescriptors(id); + for (const auto& field : fieldDescriptors) { + auto* openvdbAsset = dynamic_cast( + delegate->GetRenderIndex().GetBprim(_tokens->openvdbAsset, field.fieldId)); + if (openvdbAsset == nullptr) { + continue; + } + openvdbAsset->TrackVolumePrimitive(id); + const auto vv = delegate->Get(field.fieldId, _tokens->filePath); + if (vv.IsHolding()) { + const auto& assetPath = vv.UncheckedGet(); + auto path = assetPath.GetResolvedPath(); + if (path.empty()) { + path = assetPath.GetAssetPath(); + } +#ifdef BUILD_HOUDINI_TOOLS + if (TfStringStartsWith(path, "op:")) { + auto& fields = houVdbs[path]; + if (std::find(fields.begin(), fields.end(), field.fieldName) == fields.end()) { + fields.push_back(field.fieldName); + } + continue; + } +#endif + auto& fields = openvdbs[path]; + if (std::find(fields.begin(), fields.end(), field.fieldName) == fields.end()) { + fields.push_back(field.fieldName); + } + } + } + + _volumes.erase( + std::remove_if( + _volumes.begin(), _volumes.end(), + [&openvdbs](AtNode* node) -> bool { + if (openvdbs.find(std::string(AiNodeGetStr(node, str::filename).c_str())) == openvdbs.end()) { + AiNodeDestroy(node); + return true; + } + return false; + }), + _volumes.end()); + + for (const auto& openvdb : openvdbs) { + AtNode* volume = nullptr; + for (auto& v : _volumes) { + if (openvdb.first == AiNodeGetStr(v, str::filename).c_str()) { + volume = v; + break; + } + } + if (volume == nullptr) { + volume = AiNode(_delegate->GetUniverse(), str::volume); + AiNodeSetUInt(volume, str::id, static_cast(GetPrimId()) + 1); + AiNodeSetStr(volume, str::filename, openvdb.first.c_str()); + AiNodeSetStr(volume, str::name, id.AppendChild(TfToken(TfStringPrintf("p_%p", volume))).GetText()); + _volumes.push_back(volume); + } + const auto numFields = openvdb.second.size(); + auto* fields = AiArrayAllocate(numFields, 1, AI_TYPE_STRING); + for (auto i = decltype(numFields){0}; i < numFields; ++i) { + AiArraySetStr(fields, i, AtString(openvdb.second[i].GetText())); + } + AiNodeSetArray(volume, str::grids, fields); + } + +#ifdef BUILD_HOUDINI_TOOLS + for (auto* volume : _inMemoryVolumes) { + AiNodeDestroy(volume); + } + _inMemoryVolumes.clear(); + + const auto& houFnSet = GetHouFunctionSet(); + if (houFnSet.getVdbVolumePrimitive == nullptr || houFnSet.getHoudiniVolumePrimitive == nullptr) { + return; + } + + const auto& htoaFnSet = GetHtoAFunctionSet(); + if (htoaFnSet.convertPrimVdbToArnold == nullptr) { + return; + } + + for (const auto& houVdb : houVdbs) { + std::vector gridVec; + for (const auto& field : houVdb.second) { + auto* primVdb = houFnSet.getVdbVolumePrimitive(houVdb.first.c_str(), field.GetText()); + if (primVdb == nullptr) { + continue; + } + gridVec.push_back(primVdb); + } + if (gridVec.empty()) { + continue; + } + + auto* volume = AiNode(_delegate->GetUniverse(), str::volume); + AiNodeSetStr(volume, str::name, id.AppendChild(TfToken(TfStringPrintf("p_%p", volume))).GetText()); + htoaFnSet.convertPrimVdbToArnold(volume, static_cast(gridVec.size()), gridVec.data()); + AiNodeSetUInt(volume, str::id, static_cast(GetPrimId()) + 1); + _inMemoryVolumes.push_back(volume); + } +#endif +} + +HdDirtyBits HdArnoldVolume::GetInitialDirtyBitsMask() const { return HdChangeTracker::AllDirty; } + +HdDirtyBits HdArnoldVolume::_PropagateDirtyBits(HdDirtyBits bits) const { return bits & HdChangeTracker::AllDirty; } + +void HdArnoldVolume::_InitRepr(const TfToken& reprToken, HdDirtyBits* dirtyBits) +{ + TF_UNUSED(reprToken); + TF_UNUSED(dirtyBits); +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/render_delegate/volume.h b/render_delegate/volume.h new file mode 100755 index 0000000000..606984ed1c --- /dev/null +++ b/render_delegate/volume.h @@ -0,0 +1,117 @@ +// Copyright 2019 Luma Pictures +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/// @file volume.h +/// +/// Utilities for handling Hydra Volumes. +#pragma once + +#include +#include "api.h" + +#include + +#include "hdarnold.h" +#include "render_delegate.h" + +#include + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +/// Utility class for Hydra Volumes. +class HdArnoldVolume : public HdVolume { +public: + /// Constructor for HdArnoldVolume. + /// + /// @param delegate Pointer to the Render Delegate. + /// @param id Path to the Primitive. + /// @param instancerId Path to the Point Instancer. + HDARNOLD_API + HdArnoldVolume(HdArnoldRenderDelegate* delegate, const SdfPath& id, const SdfPath& instancerId = SdfPath()); + + /// Destructor for HdArnoldVolume. + /// + /// Frees all the Arnold Volume created. + HDARNOLD_API + ~HdArnoldVolume() override; + + /// Syncs the Hydra Volume to the Arnold Volume. + /// + /// @param sceneDelegate Pointer to the Scene Delegate. + /// @param renderPaaram Pointer to a HdArnoldRenderParam instance. + /// @param dirtyBits Dirty Bits to sync. + /// @param reprToken Token describing the representation of the volume. + HDARNOLD_API + void Sync(HdSceneDelegate* delegate, HdRenderParam* renderParam, HdDirtyBits* dirtyBits, const TfToken& reprToken) + override; + + /// Returns the initial Dirty Bits for the Primitive. + /// + /// @return Initial Dirty Bits. + HDARNOLD_API + HdDirtyBits GetInitialDirtyBitsMask() const override; + +protected: + /// Allows setting additional Dirty Bits based on the ones already set. + /// + /// @param bits The current Dirty Bits. + /// @return The new set of Dirty Bits which replace the original one. + HDARNOLD_API + HdDirtyBits _PropagateDirtyBits(HdDirtyBits bits) const override; + + /// Initialize a given representation for the volume. + /// + /// @param reprName Name of the representation to initialize. + /// @param dirtyBits In/Out HdDirtyBits value, that allows the _InitRepr + /// function to set additional Dirty Bits if required for a given + /// representation. + HDARNOLD_API + void _InitRepr(const TfToken& reprToken, HdDirtyBits* dirtyBits) override; + + /// Creates the volumes for the primitive. + /// + /// In Hydra each volume is connected to several grid/field primitives + /// where each grid/field has a name and file path associated. In Arnold + /// each Volume loads one or more grids from a file, so in this function + /// we check each grid/field connected, and create multiple Volume + /// primitives for each file loaded. + /// + /// @param id Path to the Primitive. + /// @param delegate Pointer to the Scene Delegate. + HDARNOLD_API + void _CreateVolumes(const SdfPath& id, HdSceneDelegate* delegate); + + HdArnoldRenderDelegate* _delegate; ///< Pointer to the Render Delegate. + std::vector _volumes; ///< Vector storing all the Volumes created. +#ifdef BUILD_HOUDINI_TOOLS + std::vector _inMemoryVolumes; ///< Vectoring storing all the Volumes for in-memory VDB storage. +#endif +}; + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/schemas/SConscript b/schemas/SConscript new file mode 100755 index 0000000000..7b667454c1 --- /dev/null +++ b/schemas/SConscript @@ -0,0 +1,210 @@ +# vim: filetype=python +# Copyright 2019 Autodesk, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +## load our own python modules +from utils import system +from utils.build_tools import find_files_recursive +from utils.system import IS_WINDOWS, IS_DARWIN, IS_LINUX + +import os +import platform +import sys +import shutil +import filecmp + +# import build env +Import('env') +myenv = env.Clone() + +dylib = 'PATH' if IS_WINDOWS else ('DYLD_LIBRARY_PATH' if IS_DARWIN else 'LD_LIBRARY_PATH') +env_separator = ';' if IS_WINDOWS else ':' + +arnoldPythonPath = myenv['ARNOLD_PYTHON'].replace('$ARNOLD_PATH', myenv['ARNOLD_PATH']) +myenv.AppendENVPath('PYTHONPATH', arnoldPythonPath, envname='ENV', sep=env_separator, delete_existing=1) +os.environ['PYTHONPATH'] = myenv['ENV']['PYTHONPATH'] +os.putenv('PYTHONPATH', os.environ['PYTHONPATH']) +sys.path.append(arnoldPythonPath) + +myenv.AppendENVPath(dylib, os.path.join(myenv['ARNOLD_PATH'], 'bin'), envname='ENV', sep=env_separator, delete_existing=1) +os.environ['PATH'] = myenv['ENV']['PATH'] +os.putenv('PATH', os.environ['PATH']) + +# Otherwise generating the node definitions complain about the lack of optix library on centos. +if IS_LINUX: + os.environ[dylib] = '%s:%s' % (os.environ.get(dylib, ''), myenv['ENV'][dylib]) + os.putenv(dylib, os.environ[dylib]) + +schemasBuildBase = os.path.join(env['ROOT_DIR'], env['BUILD_BASE_DIR'], 'schemas') +schemasBuildFolder = os.path.join(schemasBuildBase, 'source') + +schemaFile = os.path.join(schemasBuildBase, 'schema.usda') +schemaPreviousFile = '{}.bak'.format(schemaFile) +generateSchemaFiles = (not os.path.exists(schemaPreviousFile)) + +''' +First, call the script createSchemaFiles that will create a file schemas.usda. +It will iterate over all Arnold node types, and will add an entry in the file for its definition. +''' +# OSX's python can't find the createSchemaFile.py unless the full path is given. +os.system('python %s "%s"' % (os.path.join(env['ROOT_DIR'], 'schemas', 'createSchemaFile.py'), schemasBuildBase)) + +''' +At this point we've dynamically created the file schema.usda containing all the node entries and parameter definitions. +We now need to run usdGenSchema (provided in USD distribution) in order to generate lots of C++ files (one for each class). +For now we're not storing these C++ files as they're meant to be generated dynamically, however if we want to add custom +functions in our schema classes, we might want to added these generated cpp files to our repo +(note that it's possible to add functions that will remain even after usdGenSchema is executed once again) + +First, we'll compare the new schema.usda file with the eventual existing one that we copied as a backup. +If it's identical, we don't need to run usdGenSchema. + +FIXME Current issues to address the generation of the schema files : + - We need to double-check if matrix parameters are written the right way + - arnold compare shader's parameter 'test' is currently skipped, we need to investigate why it's failing + - we have some conflicts when different parameter names / enum values have the same string with a different case. For example A / a, Ng / ng, etc... + As a workaround I'm setting all the 1-length tokens to lower case, and I have a special exception for Ng and Ns. But that should be fixed somehow + - token 'auto' is a problem too, I'm currently calling it 'param_auto' so if there's no other solution we'll need some extra-logic when we read the schema files + - when I build the schemas, I get "Warning C4273: inconsistent linkage" for every function +''' + +genSchema = os.path.join(env['USD_PATH'], 'bin', 'usdGenSchema') +if not os.path.exists(genSchema): + print 'Command {} not found. Impossible to generate Schemas'.format(genSchema) + Return ([]) + +if not os.path.exists(schemasBuildFolder): + os.makedirs(schemasBuildFolder) + generateSchemaFiles = True +elif os.path.exists(schemaPreviousFile): + # we have a backup file. Let's compare it with the new one to see if it has changed + generateSchemaFiles = (not filecmp.cmp(schemaPreviousFile, schemaFile)) + +if generateSchemaFiles: + if os.path.exists(schemasBuildFolder): + print 'Cleaning existing schema files' + prevFiles = os.listdir(schemasBuildFolder) + for f in prevFiles: + os.remove(os.path.join(schemasBuildFolder, f)) + + print 'Now running usdGenSchema to create the C++ files...' + cmd = '{genSchema} {schemaFile} {output}'.format(**{ + 'genSchema': genSchema, + 'schemaFile': schemaFile, + 'output': schemasBuildFolder + }) + os.system(cmd) + + # We need to edit the outputted plugInfo.json file to set the library + # path properly. + # TODO: handle this for all platforms, including windows + f = open(os.path.join(schemasBuildFolder, 'plugInfo.json'), 'r') + contents = f.read() + if IS_LINUX: + contents = contents.replace('"LibraryPath": "../../libusd.so"', '"LibraryPath": "../../libusdArnold.so"') + elif IS_DARWIN: + contents = contents.replace('"LibraryPath": "../../libusd.dylib"', '"LibraryPath": "../../libusdArnold.dylib"') + else: + contents = contents.replace('"LibraryPath": "../../usd.dll"', '"LibraryPath": "../../usdArnold.dll"') + f = open(os.path.join(schemasBuildFolder, 'plugInfo.json'), 'w') + f.write(contents) + +''' +Now, last step : We need to compile the files in "schemas/build" +in order to get a library that can be accessed by USD. This way, our arnold schemas will be known by USD +''' + +source_files = [] +header_files = [] +wrapper_source_files = [os.path.join(schemasBuildBase, 'wrapModule.cpp')] + +if os.path.exists(schemasBuildFolder): + buildFiles = os.listdir(schemasBuildFolder) + for f in buildFiles: + ext = os.path.splitext(f)[1] + if ext == '.cpp': + if f.startswith('wrap'): + wrapper_source_files.append(os.path.join(schemasBuildFolder, f)) + else: + source_files.append(os.path.join(schemasBuildFolder, f)) + elif ext == '.h': + header_files.append(os.path.join(schemasBuildFolder, f)) + +source_files.append('moduleDeps.cpp') + +# Compiler flags +if not IS_WINDOWS: + myenv.Append(CXXFLAGS = Split('-fPIC -Wno-deprecated-register')) + +# Include paths +includePaths = [ + '.', + env['USD_INCLUDE'], + env['BOOST_INCLUDE'], + env['PYTHON_INCLUDE'] +] + +myenv.Append(CPPPATH = includePaths) + +# Library paths and libraries +libPaths = [ + env['PYTHON_LIB'] +] + +if env['USD_BUILD_MODE'] == 'shared_libs': + usd_deps = [ + 'arch', + 'sdf', + 'tf', + 'usd', + 'ar', + 'usdGeom', + 'usdShade', + 'vt', + 'usdLux', + 'tbb', + ] +else: + usd_deps = [ + env['USD_MONOLITHIC_LIBRARY'], + 'tbb', + ] +libPaths.append(env['USD_LIB']) +myenv.Append(LIBS = usd_deps) +myenv.Append(LIBPATH = libPaths) +if env['USD_HAS_PYTHON_SUPPORT']: + myenv.Append(LIBS = [env['PYTHON_LIB_NAME'], env['BOOST_LIB_NAME'] % 'python']) +myenv.Append(CPPDEFINES = {'MFB_PACKAGE_NAME' : 'usdArnold'}) + +mywrapperenv = myenv.Clone() +myenv.Append(CPPDEFINES = ['USDARNOLD_EXPORTS']) +# Build shared library for the Alembic procedural +USD_ARNOLD = myenv.SharedLibrary('usdArnold', source_files) + +mywrapperenv.Append(LIBPATH = [os.path.join(env['ROOT_DIR'], env['BUILD_BASE_DIR'], 'schemas')]) +mywrapperenv.Append(LIBS = ['usdArnold']) +# We need .so even on darwin +if IS_DARWIN: + mywrapperenv['SHLIBSUFFIX'] = '.so' + +USD_ARNOLD_WRAPPER = mywrapperenv.SharedLibrary('_usdArnold', wrapper_source_files, LIBPREFIX='') +Depends(USD_ARNOLD_WRAPPER, USD_ARNOLD) +generatedSchema = os.path.join(schemasBuildFolder, 'generatedSchema.usda') +plugInfo = os.path.join(schemasBuildFolder, 'plugInfo.json') +Return([ + 'USD_ARNOLD', + 'USD_ARNOLD_WRAPPER', + 'schemaFile', + 'generatedSchema', + 'plugInfo', + 'header_files']) diff --git a/schemas/__init__.py b/schemas/__init__.py new file mode 100755 index 0000000000..6a049164d1 --- /dev/null +++ b/schemas/__init__.py @@ -0,0 +1,34 @@ +# Copyright 2019 Autodesk, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# TODO: figure out what's missing from the build. CMake based builds work +# without this. +# We are forcing the creation of wrappers. +from pxr import Usd, UsdGeom, UsdShade, UsdLux +import _usdArnold +del Usd, UsdGeom, UsdShade, UsdLux +from pxr import Tf +Tf.PrepareModule(_usdArnold, locals()) +del Tf + +try: + import __DOC + __DOC.Execute(locals()) + del __DOC +except Exception: + try: + import __tmpDoc + __tmpDoc.Execute(locals()) + del __tmpDoc + except: + pass \ No newline at end of file diff --git a/schemas/createSchemaFile.py b/schemas/createSchemaFile.py new file mode 100755 index 0000000000..cd1f4a07c6 --- /dev/null +++ b/schemas/createSchemaFile.py @@ -0,0 +1,444 @@ +# Copyright 2019 Autodesk, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +## load our own python modules +import os +import platform +import sys +import filecmp +import arnold as ai + +if len(sys.argv) < 2: + print 'Not enough arguments!' + sys.exit(1) + +def getParameterStr(paramType, paramValue = None, paramEntry = None): + typeStr = '' + valueStr = '' + optionsStr = '' + if paramType == ai.AI_TYPE_BYTE: + typeStr = 'uchar' + if paramValue: + valueStr = str(paramValue.contents.BYTE) + elif paramType == ai.AI_TYPE_INT: + typeStr = 'int' + if paramValue: + valueStr = str(paramValue.contents.INT) + elif paramType == ai.AI_TYPE_UINT: + typeStr = 'uint' + if paramValue: + valueStr = str(paramValue.contents.UINT) + elif paramType == ai.AI_TYPE_BOOLEAN: + typeStr = 'bool' + if paramValue: + valueStr = 'true' if paramValue.contents.BOOL else 'false' + elif paramType == ai.AI_TYPE_FLOAT: + typeStr = 'float' + if paramValue: + valueStr = str(paramValue.contents.FLT) + elif paramType == ai.AI_TYPE_RGB: + typeStr = 'color3f' + if paramValue: + rgbVal = paramValue.contents.RGB + valueStr = '({},{},{})'.format(str(rgbVal.r), str(rgbVal.g), str(rgbVal.b)) + elif paramType == ai.AI_TYPE_RGBA: + typeStr = 'color4f' + if paramValue: + rgbaVal = paramValue.contents.RGBA + valueStr = '({},{},{},{})'.format(str(rgbaVal.r), str(rgbaVal.g), str(rgbaVal.b), str(rgbaVal.a)) + elif paramType == ai.AI_TYPE_VECTOR: + typeStr = 'vector3f' # vector3f + if paramValue: + vecVal = paramValue.contents.VEC + valueStr = '({},{},{})'.format(str(vecVal.x), str(vecVal.y), str(vecVal.z)) + elif paramType == ai.AI_TYPE_VECTOR2: + typeStr = 'float2' + if paramValue: + vec2Val = paramValue.contents.VEC2 + valueStr = '({},{})'.format(str(vec2Val.x), str(vec2Val.y)) + elif paramType == ai.AI_TYPE_STRING: + typeStr = 'string' + if paramValue: + strVal = str(paramValue.contents.STR) + valueStr = '"{}"'.format(str(strVal)) + + # FIXME: matrix parameter is an array + elif paramType == ai.AI_TYPE_MATRIX: + typeStr = 'matrix4d' + if paramValue: + if paramValue.contents.pMTX is None: + return '', '', '' + mtxVal = paramValue.contents.pMTX[0] + valueStr = '(({},{},{},{}),({},{},{},{}),({},{},{},{}),({},{},{},{}))'.format(mtxVal[0][0], mtxVal[0][1], mtxVal[0][2], mtxVal[0][3], mtxVal[1][0],\ + mtxVal[1][1],mtxVal[1][2],mtxVal[1][3],\ + mtxVal[2][0], mtxVal[2][1], mtxVal[2][2],\ + mtxVal[2][3], mtxVal[3][0],mtxVal[3][1],\ + mtxVal[3][2],mtxVal[3][3]) + elif paramType == ai.AI_TYPE_ENUM: + typeStr = 'token' + paramEnum = ai.AiParamGetEnum(paramEntry) + if paramValue: + intVal = paramValue.contents.INT + strVal = str(ai.AiEnumGetString(paramEnum, intVal)) + if len(strVal) == 1: + strVal = strVal.lower() + + # FIXME we still have a problem with parameter "auto" as it creates a token that can't be parsed properly in the generated file tokens.h + if strVal == 'auto': + strVal = 'param_auto' + + valueStr = '"{}"'.format(strVal) + optionsStr = '\n allowedTokens = [' + + i = 0 + while True: + t = ai.AiEnumGetString(paramEnum, i) + if t is None: + break + + # FIXME below are some special cases that cause problems in the schema tokens + if len(t) == 1: + t = t.lower() + if t == 'Ng': + t = 'ng' + if t == 'Ns': + t = 'ns' + if t == 'auto': + t = "param_auto" + + if i > 0: + optionsStr += ',' + optionsStr += '"{}"'.format(t) + i += 1 + optionsStr += ']' + + elif paramType == ai.AI_TYPE_CLOSURE: + typeStr = 'color4f' + valueStr = '(0,0,0,0)' + + return typeStr, valueStr, optionsStr + +''' +Convert an Arnold Param Entry to a USD declaration +and return it as a string +''' +def arnoldToUsdParamString(paramEntry): + ret = '' + paramName = ai.AiParamGetName(paramEntry) + if paramName == 'name': + return '' # nothing to return for attribute 'name' + + optionsStr = "customData = {string apiName = \"arnold_%s\"}" % paramName + if len(paramName) == 1: + paramName = paramName.lower() + + + ''' + // TODO: + // AI_TYPE_POINTER + // AI_TYPE_NODE + // AI_TYPE_USHORT + // AI_TYPE_HALF + // AI_TYPE_UNDEFINED + // AI_TYPE_NONE + ''' + paramType = ai.AiParamGetType(paramEntry) + paramDefault = ai.AiParamGetDefault(paramEntry) + paramVal = '' + optionsStr = '' + + if paramType != ai.AI_TYPE_ARRAY: + typeStr, valueStr, optionsValStr = getParameterStr(paramType, paramDefault, paramEntry) + if typeStr is None or typeStr == '': + return '' + + ret += typeStr + paramVal = valueStr + optionsStr += optionsValStr + ret += ' arnold:{} = {} ({})'.format(paramName, paramVal, optionsStr) + + else: + # Array parameter + arrayVal = paramDefault.contents.ARRAY + if arrayVal is None or arrayVal[0] is None: + return '' + arrayVal = arrayVal[0] + arrayType = ai.AiArrayGetType(arrayVal) + typeStr, valueStr, optionsValStr = getParameterStr(arrayType) + if typeStr is None or typeStr == '': + return '' + + ret += '{}[] arnold:{}'.format(typeStr, paramName) + + # FIXME do we need to set the API name ? + # ret += ' (customData = {string apiName = "arnold{}"}\n'.format(GetCamelCase(paramName)) + return ret + +def makeCamelCase(name): + return ''.join(x.capitalize() or '_' for x in name.split('_')) + +''' +Let's create the file schema.usda +and add the headers +''' +if not os.path.exists(sys.argv[1]): + os.makedirs(sys.argv[1]) +schemaFile = os.path.join(sys.argv[1], 'schema.usda') +schemaPreviousFile = '{}.bak'.format(schemaFile) +if os.path.exists(schemaPreviousFile): + os.remove(schemaPreviousFile) + +# backup the current schema.usda file, to see if it changed +if os.path.exists(schemaFile): + os.rename(schemaFile, schemaPreviousFile) + +# This is typically named 'module.cpp' in USD modules, but we name it +# 'wrapModule.cpp', so every python module related file has the name 'wrap'. + +file_module = open(os.path.join(sys.argv[1], 'wrapModule.cpp'), 'w') + +file_module.write( +'''#include +#include + +PXR_NAMESPACE_USING_DIRECTIVE + +TF_WRAP_MODULE +{ + +''' +) + +file = open(schemaFile, 'w') +file.write( +'''#usda 1.0 +( +"This file describes the Arnold USD schemas." + subLayers = [ + @usd/schema.usda@, + @usdGeom/schema.usda@, + @usdShade/schema.usda@, + @usdLux/schema.usda@ + ] +) +over "GLOBAL" ( + customData = { + string libraryName = "usdArnold" + string libraryPath = "./" + string libraryPrefix = "Usd" + string tokensPrefix = "UsdArnold" + } +) { +} +''' +) + +def createArnoldClass(entryName, parentClass, paramList, nentry, parentParamList = None, isAPI = False): + + schemaName = 'Arnold{}'.format(makeCamelCase(entryName)) + + if isAPI: + file.write('class "{}API"(\n'.format(schemaName)) + parentClass = 'APISchemaBase' + else: + file.write('class {} "{}"(\n'.format(schemaName, schemaName)) + + file.write(' inherits = []\n'.format(parentClass)) + file.write(') {\n') + + for param in paramList: + if param == 'name': + continue # nothing to do with attribute 'name' + if entryName == 'compare' and param == 'test': # we have a problem with token test from shader compare (==, !=, <, >, etc...) + continue + if parentParamList and param in parentParamList: # if this parameter already exists in the parent class we don't add it here + continue + paramEntry = ai.AiNodeEntryLookUpParameter(nentry, param) + if paramEntry == None: + print 'Param Entry not found: {}.{}'.format(entryName, param) + continue + + paramStr = arnoldToUsdParamString(paramEntry) + if paramStr != None and len(paramStr) > 0: + file.write(' {}\n'.format(paramStr)) + + file.write('}\n') + + if isAPI: + file_module.write(' TF_WRAP(Usd%sAPI);\n' % schemaName) + else: + file_module.write(' TF_WRAP(Usd%s);\n' % schemaName) + + +''' +Here we want to generate a file schema.usda containing all the arnold node entries as new schemas +We will then run usdGenSchema schema.usda in order to generate all the c++ schema classes. +After that we'll need to compile these classes in a library that will have to be accessed by USD to know arnold schemas + +The Arnold schemas will be named arnold_polymesh, arnold_standard_surface, etc... +Instead of having lots of separate schemas, we're going to group them by type. +Thus each arnold node entry type (shape, shader, operator, etc...) will have a corresponding schema with the common parameters. +The schemas for each node entry will then derive from their "type" schema + +For example, we want a schema "arnold_light" defining the parameters +"color", "intensity", "exposure", etc... +and then "arnold_skydome_light" deriving from "arnold_light" and defining the additional skydome parameters. + +That's not a simple information to get from Arnold as there's no API to get info about a node entry type. +So below we're going to list the arnold node entries, check their type and list of parameters. +For example, in order to get the list of parameters for "arnold_light", we're going to compute the union of +all parameters for in "arnold_skydome_light", "arnold_distant_light", "arnold_point_light", "arnold_quad_light", etc... +In theory we should also compare the parameter types and their default values, from AFAIK we shouldn't have this problem in the current set of arnold nodes +''' +ai.AiBegin() + +entryList = [] # list of [nodeEntryName, nodeEntryTypeName, parametersList ] +entryByType = {} # dictionary (key= nodeEntryTypeName, value=list of nodeEntryName for this type) +typeParams = {} # dictionary (key=nodeEntryTypeName, value= list of parameters which exist in ALL the corresponding nodeEntryName) + +# Loop over node entries +nodeEntryIter = ai.AiUniverseGetNodeEntryIterator(ai.AI_NODE_ALL) +while not ai.AiNodeEntryIteratorFinished(nodeEntryIter): + nentry = ai.AiNodeEntryIteratorGetNext(nodeEntryIter); + + # Name of this AtNodeEntry (distant_light, skydome_light, etc...) + entryName = str(ai.AiNodeEntryGetName(nentry)) + # Type of this AtNodeEntry (light, shape, shader, operator, etc...) + entryTypeName = str(ai.AiNodeEntryGetTypeName(nentry)) + + # Get the list of parameters for this node entry + paramsList = [] + + # Loop over AtParamEntry for this AtNodeEntry + paramsIter = ai.AiNodeEntryGetParamIterator(nentry) + while not ai.AiParamIteratorFinished(paramsIter): + paramEntry = ai.AiParamIteratorGetNext(paramsIter) + # Add this parameter name to our list + paramsList.append(ai.AiParamGetName(paramEntry)) + ai.AiParamIteratorDestroy(paramsIter) # iterators need to be deleted + + # Add an element in my list of node entries, with its name, type name, and list of parameters + entryList.append([entryName, entryTypeName, paramsList]) + + if entryByType.get(entryTypeName) is None: + # first time we find a node with this type, let's make the dict value a list + entryByType[entryTypeName] = [] + + # Add this node entry to its "type" dictionary + entryByType[entryTypeName].append(entryName) + + if typeParams.get(entryTypeName) is None: + # first time we find a node with this type, let's simply copy all parameters for this node entry + typeParams[entryTypeName] = paramsList + else: + # We want the final list to be the union between the existing list and paramsList + # So first we copy the existing list for this type + prevParamList = typeParams[entryTypeName] + # We create a new list that we'll set afterwards + newList = [] + for prevParam in prevParamList: + # for each of the existing parameters, we check if it also exists in this node entry + if prevParam in paramsList: + # it also exists, let's add it back to our list + newList.append(prevParam) + # Setting the updated list of parameters back to our dictionary + typeParams[entryTypeName] = newList + +ai.AiNodeEntryIteratorDestroy(nodeEntryIter) # iterators need to be deleted + +''' +Now let's create a new class for each "type", let it inherit from a meaningful schema, and let's add its parameters based on the existing dictionary +''' +for key, paramList in typeParams.iteritems(): + if key == 'options' or key == 'override': + continue + + blacklistParams = [] + + parentClass = 'Typed' + if key == 'shader': + parentClass = 'Shader' + elif key == 'light': + parentClass = 'Light' + blacklistParams = ['intensity', 'color', 'exposure', 'diffuse', 'specular', 'normalize', 'matrix'] + elif key == 'shape': + parentClass = 'Boundable' # FIXME should it be imageable ? + blacklistParams = ['matrix'] + elif key == 'camera': + parentClass = 'Camera' + elif key == 'operator': + parentClass = 'NodeGraph' + + entryNames = entryByType[key] # list of entry names for this type + if entryNames == None or len(entryNames) == 0: + print 'This script is not working...no entries found for type {}'.format(key) + + entryName = entryNames[0] # using the first entry found here + nentry = ai.AiNodeEntryLookUp(entryName) + if nentry == None: + print 'Hey I could not find any AtNodeEntry called {}'.format(entryName) + continue + + createArnoldClass(key, parentClass, paramList, nentry, None, False) + + # Now Create the API schema for lights and shapes + if key == 'light' or key == 'shape': + createArnoldClass(key, 'APISchemaBase', paramList, nentry, blacklistParams, True) + +# list of the node entries that need an API schema, along with the list of parameters to ignore +nativeUsdList = { + 'polymesh': ['nsides', 'vidxs', 'polygon_holes', 'nidxs', 'matrix', 'shader'], + 'curves' : ['num_points', 'points', 'radius', 'matrix', 'shader'], + 'points' : ['matrix', 'shader', 'points', 'radius'], + 'box' : ['min', 'max', 'matrix', 'shader'], + 'sphere' : ['radius', 'min', 'max', 'matrix', 'shader'], + 'cylinder' : ['radius', 'matrix', 'shader'], + 'cone' : ['bottom_radius', 'matrix', 'shader'], + 'distant_light' : ['angle', 'intensity', 'color', 'exposure', 'diffuse', 'specular', 'normalize', 'matrix'], + 'skydome_light' : ['filename', 'format', 'intensity', 'color', 'exposure', 'diffuse', 'specular', 'normalize', 'matrix'], + 'disk_light' : ['radius', 'intensity', 'color', 'exposure', 'diffuse', 'specular', 'normalize', 'matrix'], + 'quad_light' : ['vertices', 'filename', 'intensity', 'color', 'exposure', 'diffuse', 'specular', 'normalize', 'matrix'], + 'mesh_light' : ['mesh', 'intensity', 'color', 'exposure', 'diffuse', 'specular', 'normalize', 'matrix'] + } + +for entry in entryList: + entryName = entry[0] + entryTypeName = entry[1] + parametersList = entry[2] + nentry = ai.AiNodeEntryLookUp(entryName) + if nentry == None: + print 'I could not find any AtNodeEntry called {}'.format(entryName) + continue + + parentClass = 'Arnold{}'.format(makeCamelCase(entryTypeName)) + if entryName == 'options' or entryName == 'override': + continue # do we want to create schemas for the options ? + + createArnoldClass(entryName, parentClass, parametersList, nentry, typeParams[entryTypeName], False) + + if entryName in nativeUsdList: + createArnoldClass(entryName, 'APISchemaBase', parametersList, nentry, nativeUsdList[entryName], True) + +''' +Ok, all this was just for the "Typed" Schemas, where each arnold node type has a counterpart schema. +Now, we also want to have API schemas, so that people can get/set arnold attributes on a USD-native node type +''' + +file_module.write('}\n') + +# We're done with this file, we can close it now +file_module.close() +file.close() + +# We're done with Arnold, let's end the session +ai.AiEnd() diff --git a/schemas/moduleDeps.cpp b/schemas/moduleDeps.cpp new file mode 100755 index 0000000000..13b5648f3f --- /dev/null +++ b/schemas/moduleDeps.cpp @@ -0,0 +1,33 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include +#include +#include +#include + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +TF_REGISTRY_FUNCTION(TfScriptModuleLoader) +{ + const std::vector reqs = { + TfToken("ar"), TfToken("arch"), TfToken("gf"), TfToken("js"), TfToken("kind"), + TfToken("pcp"), TfToken("plug"), TfToken("sdf"), TfToken("tf"), TfToken("usd"), + TfToken("usdGeom"), TfToken("usdShade"), TfToken("usdLux"), TfToken("vt"), TfToken("work"), + }; + TfScriptModuleLoader::GetInstance().RegisterLibrary(TfToken("usdArnold"), TfToken("UsdArnold"), reqs); +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/testsuite/SConscript b/testsuite/SConscript new file mode 100755 index 0000000000..c74306b6b7 --- /dev/null +++ b/testsuite/SConscript @@ -0,0 +1,765 @@ +# vim: filetype=python + +import sys, os, glob, shutil, time, subprocess + +## load third-party python modules +from utils.contrib.bottle import SimpleTemplate + +## load our own python modules +import utils as sa +from utils.build_tools import process_return_code +from utils.regression_test import Test +from utils.system import print_safe, IS_WINDOWS, IS_LINUX, IS_DARWIN +from utils.test_stats import * +from utils.testsuite import * +from utils.valgrind import * + +Import('env') + +# Total running time for all tests +TOTAL_RUNNING_TIME = 0 + +## define some variables in use by multiple tests +root_path = env.Dir('#').abspath +kick_path = env['ARNOLD_BINARIES'] + +if '$ARNOLD_PATH' in kick_path: + kick_path = kick_path.replace('$ARNOLD_PATH', env['ARNOLD_PATH']) + + + +oiiotool_path = os.path.join(root_path, 'contrib', 'OpenImageIO', 'bin', sa.system.os, 'oiiotool') +maketx_path = os.path.join(root_path, 'contrib', 'OpenImageIO', 'bin', sa.system.os, 'maketx') +testsuite_common = os.path.abspath(os.path.join('testsuite', 'common')) +move_command = IS_WINDOWS and '$move /Y' or '$mv' + +def list_tests(target, source, env): + for file in source: + name = os.path.basename(os.path.dirname(str(file))) + with open(str(file), 'r') as f: + summary = f.readline().strip('\n') + print_safe('%s: %s' % (name, summary)) + print_safe("%s matches" % len(source)) + return None + +listtest_bld = Builder(action = Action(list_tests, "Listing tests...")) + +def list_test_scripts(target, source, env): + for file in source: + name = os.path.basename(os.path.dirname(str(file))) + test = Test.CreateTest(name, globals()) + test.generate_command_line(os.path.join('testsuite', name)) + print_safe("%s:" % name) + for line in test.script.splitlines(): + print_safe(" %s" % line) + print_safe("") + print_safe("%s matches" % len(source)) + return None + +listtestscripts_bld = Builder(action = Action(list_test_scripts, "Listing test scripts...")) + +def list_test_errors(target, source, env): + for file in source: + dirname = os.path.dirname(str(file)) + name = os.path.basename(dirname) + with open(str(file), 'r') as f: + value = f.readline().strip('\n') + if value != 'OK': + print_safe('%s: %s' % (name, value)) + with open(os.path.join(dirname, name + '.log'), 'r') as l: + while True: + line = l.readline().strip('\n') + if line == "": + # We have reached the end of file. + break + if (line.lower().find('error') != -1) or (line.lower().find('warning') != -1): + print_safe(line) + return None + +listtesterrors_bld = Builder(action = Action(list_test_errors, "Listing broken tests...")) + +## Creates a new test in the testsuite directory +def make_test(target, source, env): + testpath = str(target[0]) + testname = os.path.basename(testpath) + os.mkdir(testpath) + os.mkdir(os.path.join(testpath, 'data')) + os.mkdir(os.path.join(testpath, 'ref')) + shutil.copy(os.path.join(testsuite_common, 'README.template'), os.path.join(testpath, 'README')) + shutil.copy(os.path.join(testsuite_common, 'test.ass.template'), os.path.join(testpath, 'data', 'test.ass')) + return None ## always succeeds + +maketest_bld = Builder(action = Action(make_test, "Creating test '$TARGET'...")) + +## Make a list of groups +def list_groups(target, source, env): + + def count_tests_in_group(group): + count = 0 + tests = find_test_group(group, env) + count += len(tests) + for test in tests: + if not test.startswith('test_'): + # We found a nested group, count individual tests + n = count_tests_in_group(test) + count = count + n - 1 + return count + + def list_groups_in_file(file): + with open(file, 'r') as f: + comment = '' + for line in f.readlines(): + line = line.lstrip(' \t') + if line.startswith('#'): + comment = line[1:-1] + continue + (l, s, r) = line.partition(':') + if s == ':': + group = l.rstrip() + count = count_tests_in_group(group) + print_safe("%s(%s) \t %s" % (group, count, comment)) + + # First search the user local file for this group (only if the local file exists) + if os.path.exists(os.path.join('testsuite', 'groups.local')): + list_groups_in_file(os.path.join('testsuite', 'groups.local')) + + list_groups_in_file(os.path.join('testsuite', 'groups')) + + return None ## always succeeds + +listgroups_bld = Builder(action = Action(list_groups, "Listing test groups...")) + +def run_test(target, source, env): + global TOTAL_RUNNING_TIME + status = 'OK' + status_valgrind = 'OK' + TEST_NAME = env['TEST_NAME'] + + test_dir = os.path.dirname(target[0].get_abspath()) + + test_env = env.Clone() + test_env.AppendENVPath('ARNOLD_PLUGIN_PATH', os.path.dirname(test_env['USD_PROCEDURAL_PATH'])) + + + show_test_output = (test_env['SHOW_TEST_OUTPUT'] == 'always') or (test_env['SHOW_TEST_OUTPUT'] == 'single' and (len(TEST_TARGETS) == 1)) + + # Propagate our scons construction environment into a dictionary suitable for + # subprocess.Popen (only string values allowed) + local_env = {} + for k in env['ENV']: + local_env[k] = str(env['ENV'][k]) + + if test_env['ENVIRONMENT']: + for var in test_env['ENVIRONMENT']: + if show_test_output: + print_safe("Setting environment var '%s' to '%s'" % (var[0], var[1])) + local_env[var[0]] = str(var[1]) + + # Force CLM Hub to write the log files in the test working directory and + # raise the log level to "trace" in order to get the full verbosity + # (see #5658). + local_env['ADCLMHUB_LOG_DIR'] = test_dir + local_env['ADCLMHUB_LOG_LEVEL'] = 'T' + + output_image = test_env['OUTPUT_IMAGE'] + if output_image: + output_image = os.path.join(test_dir, output_image) + + ## remove any leftovers + sa.path.remove(os.path.join(test_dir, output_image)) + sa.path.remove(os.path.join(test_dir, 'new.png')) + sa.path.remove(os.path.join(test_dir, 'ref.png')) + sa.path.remove(os.path.join(test_dir, 'dif.png')) + sa.path.remove(os.path.join(test_dir, 'STATUS')) + sa.path.remove(os.path.join(test_dir, 'STATUS.vg')) + sa.path.remove(os.path.join(test_dir, '%s.vg.xml' % TEST_NAME)) + sa.path.remove(os.path.join(test_dir, 'TIMINGS')) + + nMemErrors, nMemLeaksDL, nMemLeaksPL, nMemLeaksIL, nMemLeaksSR = 0, 0, 0, 0, 0 + + for cmd in test_env['TEST_SCRIPT'].splitlines(): + if not cmd: + continue + + # Commands marked with the character '$' will be executed + # as shell bultins. We should use that for copy, move, etc in the + # windows platform (see #4085) + builtin_cmd = (cmd[0] == '$') + use_shell = builtin_cmd + if builtin_cmd: + cmd = cmd[1:] + + if cmd.startswith("./"): + cmd = os.path.join(test_dir, cmd) + + tokens = cmd.split() + if tokens[0] == 'kick': + cmd = os.path.join(kick_path, cmd) + # Append additional parameters if given + cmd += ' ' + test_env['KICK_PARAMS'] + # ARNOLD_PLUGIN_PATH is set, so we don't need -l. + + elif os.path.splitext(tokens[0])[1] == '.py': + # Use the same Python interpreter we used for launching SCons + cmd = sys.executable + ' ' + cmd + use_shell = True + + if test_env['USE_VALGRIND'] != 'False': + cmd = ''' + valgrind \ + --leak-check=full \ + --leak-resolution=high \ + --show-reachable=yes \ + --num-callers=20 \ + --gen-suppressions=all \ + --suppressions=%s \ + --xml=yes \ + --xml-file=%s.vg.xml ''' % ( os.path.join(testsuite_common, 'valgrind.supp'), os.path.join(test_dir, TEST_NAME) ) + cmd + + before_time = time.time() + # NOTE #5079: Execute the test printing the logs to the standard output + # if requested (parameter verbose), and always write them to a .log file. + + print '====Exec %s' % cmd + print os.getenv('PATH') + + retcode, out = sa.system.execute(cmd, cwd=test_dir, env=local_env, shell=use_shell, timeout=test_env.get('TIMELIMIT', 0), verbose=show_test_output) + with open(os.path.join(test_dir, "%s.log") % TEST_NAME, 'w') as f: + f.writelines(l + '\n' for l in out) + + running_time = time.time() - before_time + TOTAL_RUNNING_TIME += running_time + if test_env['USE_VALGRIND'] != 'False': + # Parse Valgrind Output + nMemErrors, nMemLeaksDL, nMemLeaksPL, nMemLeaksIL, nMemLeaksSR = vg_count_errors("%s.vg.xml" % os.path.join(test_dir, TEST_NAME)) + if test_env['USE_VALGRIND'] == 'Full': + nMemLeaks = nMemLeaksDL + nMemLeaksPL + else: + nMemLeaks = nMemLeaksDL + + if nMemErrors > 0: + status_valgrind = 'MEMERROR' + elif nMemLeaks > 0: + status_valgrind = 'MEMLEAK' + + status = process_return_code(retcode) + + if test_env['FORCE_RESULT'] == 'FAILED': + # In this case, retcode interpretation is fliped (except for crashed tests) + if status == 'FAILED': + status = 'OK' + elif status == 'OK': + status = 'FAILED' + elif test_env['FORCE_RESULT'] == 'CRASHED': + if status == 'CRASHED': + status = 'OK' + elif status == 'OK': + status = 'FAILED' + + if status != 'OK': + if test_env['CONTINUE_ON_FAILURE'] == False: + break + + reference_image = test_env['REFERENCE_IMAGE'] + diff_hardfail = test_env['DIFF_HARDFAIL'] + diff_fail = test_env['DIFF_FAIL'] + diff_failpercent = test_env['DIFF_FAILPERCENT'] + diff_warnpercent = test_env['DIFF_WARNPERCENT'] + + has_diff = False + is_deep = False + channels = 'R,G,B' + alpha = 'A' + # if output is deep and determine which channels to display + if test_env['MAKE_THUMBNAILS'] and os.path.exists(reference_image) : + cmd = oiiotool_path + ' -v --info ' + reference_image + retcode, info = sa.system.execute(cmd, cwd=test_dir, env=local_env, shell=use_shell) + + print "Exec %s" % cmd + print "Info %s" % info + + is_deep = 'deep' in info[1].split(',')[-1] + channel_names = info[2].split(': ')[1].split(',') + goal_channels = ['R', 'G', 'B', 'A'] + new_channels = ['', '', '', ''] + for channel in channel_names: + channel = channel.strip().split(' ')[0] + for i in range(0, 4): + if channel[-1] == goal_channels[i] and channel != 'A' + goal_channels[i]: + if not new_channels[i]: + new_channels[i] = channel + + if not new_channels[0] or not new_channels[1] or not new_channels[2] : + channels = '0,0,0' + else: + channels = '%s,%s,%s' % tuple(new_channels[:-1]) + + if new_channels[3] : + alpha = new_channels[3] + + if status =='OK' and test_env['FORCE_RESULT'] == 'OK': + if test_env['UPDATE_REFERENCE']: + if os.path.exists(output_image): + if not reference_image: + reference_image = { + '.exr' : 'reference.exr', + '.tif' : 'reference.tif' + }.get(os.path.splitext(output_image)[1], 'reference.tif') + reference_image = os.path.abspath(os.path.join('testsuite', TEST_NAME, 'ref', reference_image)) + ## the user wants to update the reference image and log + print_safe('Updating %s ...' % reference_image) + ## NOTE(boulos): For some reason reference.tif might be read + ## only, so just remove it first. + if os.path.exists(reference_image): + sa.path.remove(reference_image) + + shutil.copy(output_image, reference_image) + reference_log = os.path.join(os.path.dirname(reference_image), 'reference.log') + print_safe('Updating %s ...' % reference_log) + shutil.copy(os.path.join(test_dir, '%s.log') % TEST_NAME, reference_log) + + if reference_image != '': + if os.path.exists(output_image) and os.path.exists(reference_image): + ## if the test passed - compare the generated image to the reference + ## and compute the diff jpeg image by substracting them, taking the absolute value, + ## and multiplying by 4 + img_diff_opt = '--threads 1 --hardfail %f --fail %f --failpercent %f --warnpercent %f' % (diff_hardfail, diff_fail, diff_failpercent, diff_warnpercent) + img_diff_cmd = ('%s ' + img_diff_opt + ' --diff %s %s') % (oiiotool_path, output_image, reference_image) + if test_env['MAKE_THUMBNAILS'] : + if is_deep : + img_diff_cmd += ' --flatten --swap --flatten --swap ' + img_diff_cmd += ' --sub --abs --cmul 8 -ch "%s,%s" --dup --ch "%s,%s,%s,0" --add -ch "0,1,2" -o dif.png ' % tuple([channels] + [alpha] * 4) + retcode, out = sa.system.execute(img_diff_cmd, cwd=test_dir, env=local_env, shell=use_shell) + with open(os.path.join(test_dir, "%s.diff.log") % TEST_NAME, 'w') as f: + f.writelines(l + '\n' for l in out) + if show_test_output: + for line in out : + print_safe(line) + + if retcode != 0: + status = 'FAILED' + + ## convert these to jpg form for makeweb + if test_env['MAKE_THUMBNAILS']: + if os.path.exists(output_image): + cmd = oiiotool_path + ' --threads 1 ' + output_image + (' --flatten ' if is_deep else '') + ' --ch ' + str(channels) + ' -o new.png' + sa.system.execute(cmd, cwd=test_dir, shell=use_shell) + else: + status = 'FAILED' + + if test_env['FORCE_RESULT'] == 'OK' and reference_image != '' and os.path.exists(reference_image) and test_env['MAKE_THUMBNAILS'] : + cmd = oiiotool_path + ' --threads 1 ' + reference_image + (' --flatten ' if is_deep else '') + ' --ch ' + str(channels) + ' -o ref.png' + sa.system.execute(cmd, cwd=test_dir, shell=use_shell) + + readme_file = os.path.join(test_dir, 'README') + + ## progress text (scream if the test didn't pass) + progress_text = '' + if status_valgrind == 'OK': + if status == 'OK': + progress_text = TEST_NAME + else: + with open(readme_file, 'r') as f: + summary = f.readline().strip('\n') + progress_text = ('%s %7s: %s') % (TEST_NAME, status, summary) + elif status_valgrind == 'MEMERROR': + with open(readme_file, 'r') as f: + summary = f.readline().strip('\n') + f.close + progress_text = '%s %s (%d): %s' % (TEST_NAME, status_valgrind, nMemErrors, summary) + elif status_valgrind == 'MEMLEAK': + with open(readme_file, 'r') as f: + summary = f.readline().strip('\n') + f.close + progress_text = '%s %s (%d): %s' % (TEST_NAME, status_valgrind, nMemLeaks, summary) + + print_safe(progress_text) + + with open(os.path.join(test_dir, 'STATUS'), 'w') as f: + f.write(status) ## so we can get the status of this test later + + if test_env['USE_VALGRIND'] != 'False': + with open(os.path.join(test_dir, 'STATUS.vg'), 'w') as f: + f.write('%d\n%d\n%d\n%d\n%d''' % (nMemErrors,nMemLeaksDL,nMemLeaksPL,nMemLeaksIL,nMemLeaksSR)) + + with open(os.path.join(test_dir, 'TIMINGS'), 'w') as f: + f.write('''%s''' % str(running_time)) + + ## get README so that we can stick it inside the html file + with open(readme_file, 'r') as f: + readme = f.read() + + ## get HTML template + with open(os.path.join(testsuite_common, 'test.html.template')) as f: + html_template = f.read() + + ## create the html file with the results + html_file = str(target[0]) + sa.path.remove(html_file) + with open(html_file, 'w') as f: + params = { + 'name': TEST_NAME, + 'status': status, + 'readme': readme, + 'new_image': os.path.exists(os.path.join(test_dir, 'new.png')) and 'new image' or ' ', + 'ref_image': os.path.exists(os.path.join(test_dir, 'ref.png')) and 'ref image' or ' ', + 'diff_image': os.path.exists(os.path.join(test_dir, 'dif.png')) and 'difference image' or ' no difference ' + } + f.write(html_template.format(**params)) + + vg_write_report(f, os.path.join(test_dir, "%s.vg.xml") % TEST_NAME, test_env['USE_VALGRIND']) + + ## always succeeds (unless some of the functions above throw an error) + return None + +runtest_bld = Builder(action = Action(run_test)) + +def process_testsuite(target, source, env): + global TOTAL_RUNNING_TIME + + ## get number of failed tests + passed, failed, crashed, memerrors, memleaks = 0, 0, 0, 0, 0 + test_statuses = {} + + for test in source: + test_dir = str(test.dir) + with open(os.path.join(test_dir, 'STATUS'), 'r') as f: + status = f.readline() ## just one line + stat = (status == 'OK') + + if status == 'OK': + passed += 1 + elif status == 'FAILED': + failed += 1 + elif status == 'CRASHED': + crashed += 1 + + if env['USE_VALGRIND'] != 'False': + with open(os.path.join(test_dir, 'STATUS.vg'), 'r') as f: + errors = f.readlines() + nMemErrors = int(errors[0]) + nMemLeaksDL = int(errors[1]) + nMemLeaksPL = int(errors[2]) + nMemLeaksIL = int(errors[3]) + nMemLeaksSR = int(errors[4]) + if env['USE_VALGRIND'] == 'Full': + nMemLeaks = nMemLeaksDL + nMemLeaksPL + else: + nMemLeaks = nMemLeaksDL + if nMemErrors > 0: + memerrors += 1 + elif nMemLeaks > 0: + memleaks += 1 + + target_dir = os.path.dirname(str(target[0])) + time_table = TimedTestTable(target_dir) + time_table.load() + time_table.timestamp() + + for test in source: + test_dir = str(test.dir) + test_name = os.path.basename(test_dir) + with open(os.path.join(test_dir, 'TIMINGS'), 'r') as f: + running_time_str = f.readline() + running_time = float(running_time_str) ## just one line + + try: + test_number = int(test_name[5:]) + time_table.add(test_number, running_time) + except (ValueError, TypeError): + pass + + time_table.save() + + ## Generate HTML report + + total_tests = len(source) + + report_params = { + 'arnold_version': env['ARNOLD_VERSION'], + 'revision': sa.git.sha1()[:8] if sa.git.sha1() else 'not found', + 'repo_url': sa.git.remote_url() or 'not found', + 'patterns': PATTERNS, + 'tags': TAGS, + 'total': total_tests, + 'passed': passed, + 'failed': failed, + 'crashed': crashed, + 'skipped': SKIPPED_TESTS['ignore'] + SKIPPED_TESTS['os'] + SKIPPED_TESTS['other'], + 'skipped_ignored': SKIPPED_TESTS['ignore'], + 'skipped_os': SKIPPED_TESTS['os'], + 'skipped_other': SKIPPED_TESTS['other'], + 'total_time': TOTAL_RUNNING_TIME, + 'use_valgrind': env['USE_VALGRIND'] != 'False', + 'tests' : [] + } + + if env['USE_VALGRIND'] != 'False': + report_params['memerrors'] = memerrors + report_params['memleaks'] = memleaks + + if env['SHOW_PLOTS']: + time_table.generate_plots() + report_params['time_plots_image'] = 'plot_rt-sup.png' + + for test in source: + test_dir = str(test.dir) + test_name = os.path.basename(test_dir) + test_link = os.path.join(test_name, os.path.basename(str(test))) + with open(os.path.join(test_dir, 'STATUS'), 'r') as f: + status = f.readline() ## just one line + with open(os.path.join(test_dir, 'README'), 'r') as f: + summary = f.readline() ## summary is on the first line + description = f.read() ## description is the rest + + nMemErrors, nMemLeaks = 0, 0 + if env['USE_VALGRIND'] != 'False': + with open(os.path.join(str(test.dir), 'STATUS.vg'), 'r') as f: + errors = f.readlines() + nMemErrors = int(errors[0]) + nMemLeaksDL = int(errors[1]) + nMemLeaksPL = int(errors[2]) + nMemLeaksIL = int(errors[3]) + nMemLeaksSR = int(errors[4]) + if env['USE_VALGRIND'] == 'Full': + nMemLeaks = nMemLeaksDL + nMemLeaksPL + else: + nMemLeaks = nMemLeaksDL + + try: + test_number = int(test_name[5:]) + report_params['tests'].append({ + 'name': test_name, + 'url': test_link, + 'descr_summary': summary, + 'descr_details': description, + 'status': { 'OK': 'passed', 'FAILED': 'failed', 'CRASHED': 'crashed' }[status], + 'time': time_table._data[-1][test_number].timing, + 'new_img': os.path.exists(os.path.join(test_dir, 'new.png')) and test_name + '/new.png' or '', + 'ref_img': os.path.exists(os.path.join(test_dir, 'ref.png')) and test_name + '/ref.png' or '', + 'dif_img': os.path.exists(os.path.join(test_dir, 'dif.png')) and test_name + '/dif.png' or '', + 'mem_leaks': nMemLeaks, + 'mem_errors': nMemErrors + }) + except (ValueError, TypeError): + pass + + ## Render report to HTML file using template + with open(os.path.join(testsuite_common, 'testsuite.html.template'), 'r') as template_file: + with open(str(target[0]), 'w') as report_file: + report_file.write(SimpleTemplate(template_file.read()).render(report_params).encode('utf8')) + + ## Report results in console + + result_string = 'Ran %d regression tests' % (len(source)) + skipped = SKIPPED_TESTS['ignore'] + SKIPPED_TESTS['os'] + SKIPPED_TESTS['other'] + + if skipped > 0: + result_string += ' (%d skipped)' % skipped + + if failed + crashed == 0: + result_string += ' - ALL TESTS OK' + elif failed == 0: + result_string += ' - %d crashed!' % crashed + elif crashed == 0: + result_string += ' - %d failed!' % failed + else: + result_string += ' - %d failed and %d crashed!' % (failed, crashed) + + if env['USE_VALGRIND'] != 'False': + if memerrors == 0: + result_string += ', NO MEMORY ERRORS' + else: + result_string += ', %d with memory errors!' % (memerrors) + if memleaks == 0: + result_string += ', NO MEMORY LEAKS' + else: + result_string += ', %d with memory leaks!' % (memleaks) + + print_safe(result_string) + print_safe('View testsuite results at: file://%s\n' % os.path.abspath(str(target[0]))) + + return failed + crashed > 0 + +testsuite_bld = Builder(action = process_testsuite) + +# process build targets +TESTSUITE = [] +TEST_TARGETS = [] +TEST_NAMES = set() +TAGS = [] +PATTERNS = [] + +if IS_WINDOWS: + test_env = env.Clone(SHLIBPREFIX = '', SHLIBSUFFIX='.dll') +elif IS_DARWIN: + test_env = env.Clone(SHLIBPREFIX = '', SHLIBSUFFIX='.dylib') +else: + test_env = env.Clone(SHLIBPREFIX = '', SHLIBSUFFIX='.so') + +skip_ignored_tests = True + +test_env.Append(BUILDERS = {'ListTests' : listtest_bld}) +test_env.Append(BUILDERS = {'ListTestScripts' : listtestscripts_bld}) +test_env.Append(BUILDERS = {'ListGroups' : listgroups_bld}) +test_env.Append(BUILDERS = {'ListTestErrors' : listtesterrors_bld}) +test_env.Append(BUILDERS = {'MakeTest' : maketest_bld}) +test_env.Append(BUILDERS = {'RunTest': runtest_bld}) +test_env.Append(BUILDERS = {'Testsuite' : testsuite_bld}) + +# Tests compiling shaders, procedurals or using the Arnold SDK will need to locate +# the Arnold API headers/lib +test_env.Append(CPPPATH = env['ARNOLD_API_INCLUDES']) +test_env.Append(LIBPATH = env['ARNOLD_BINARIES']) +test_env.Append(LIBS = Split('ai')) + +test_env.PrependENVPath('ARNOLD_TESTSUITE_COMMON', testsuite_common) + +# Check that timelimit is a valid number +try: + timeLimit = test_env.get('TIMELIMIT', 0) + test_env['TIMELIMIT'] = float(timeLimit) +except ValueError: + test_env['TIMELIMIT'] = 0 + +## First stage. Process build targets, expanding the groups and patterns into single tests +index = 0 +while True: + if index == len(BUILD_TARGETS): + break + + target = BUILD_TARGETS[index] + + (l, s, r) = target.partition(':') + + # Target "maketest[:testname]", creates a new test in the testsuite (defaults to the next available name in ascending order) + if l == 'maketest': + if r == '': + r = get_next_test_name() + if r != '': + testpath = os.path.abspath(os.path.join('testsuite', 'test_' + r)) + if os.path.exists(testpath): + print_safe("ERROR: Test %s already exists!" % r) + else: + MAKETEST = test_env.MakeTest(testpath, None) + test_env.Alias(target, MAKETEST) + test_env.AlwaysBuild(MAKETEST) + index += 1 + elif l == 'testlist': + src = [] + tests = get_test_list(r, test_env, PATTERNS, TAGS) + for t in tests: + if os.path.exists(os.path.join('testsuite', t, 'README')): + src.append(os.path.join(t, 'README')) + src.sort() + TESTLIST = test_env.ListTests(target, src) + test_env.Alias(target, TESTLIST) + test_env.AlwaysBuild(TESTLIST) + index += 1 + elif l == 'testscripts': + src = [] + tests = get_test_list(r, test_env, PATTERNS, TAGS) + for t in tests: + if os.path.exists(os.path.join('testsuite', t, 'README')): + src.append(os.path.join(t, 'README')) + src.sort() + TESTSCRIPTS = test_env.ListTestScripts(target, src) + test_env.Alias(target, TESTSCRIPTS) + test_env.AlwaysBuild(TESTSCRIPTS) + index += 1 + elif l == 'testgroups': + TESTGROUPS = test_env.ListGroups(target, None) + test_env.Alias(target, TESTGROUPS) + test_env.AlwaysBuild(TESTGROUPS) + index += 1 + elif l == 'testerrors': + testlist = glob.glob(os.path.join(test_env.Dir('.').abspath, 'test_*')) + SRC = [] + for name in testlist: + SRC += [os.path.join(os.path.basename(name), 'STATUS')] + SRC.sort() + TESTERRORS = test_env.ListTestErrors(target, SRC) + test_env.Alias(target, TESTERRORS) + test_env.AlwaysBuild(TESTERRORS) + index += 1 + elif l == 'testsuite': + tags = r.split(',') + if 'ignore' in tags or 'all' in tags: + skip_ignored_tests = False + + tests = get_test_list(r, test_env, PATTERNS, TAGS) + for t in tests: + TEST_NAMES.add(t) + + del BUILD_TARGETS[index] + else: + if s != ':' and target.startswith('test_'): + # Expand test patterns + l = glob.glob(os.path.join("testsuite", target)) + if len(l) == 1 and os.path.basename(l[0]) == target: + TEST_NAMES.add(target) + index += 1 + elif len(l) == 0: + print_safe("WARNING: No tests matching expression \"%s\"" % target) + del BUILD_TARGETS[index] + else: + PATTERNS.append(target) + del BUILD_TARGETS[index] + for name in l: + name = os.path.basename(name) + TEST_NAMES.add(name) + else: + index += 1 + + +# Second stage. We have a flat list of single tests, so we prepare them for building + +BLACKLIST = {'ignore':[], 'os':[]} +SKIPPED_TESTS = {'ignore':0, 'os':0, 'other':0} + +# Tests in 'ignore' group are always added to the black list +BLACKLIST['ignore'] = find_test_group('ignore', env) +# Tests intended for this platform +OSTESTLIST = find_test_group(sa.system.os, env) + +# Add tests intended for other platforms to the black list +for o in sa.system.allowed.os: + if o != sa.system.os: + for atest in find_test_group(o, env): + if atest not in OSTESTLIST: + BLACKLIST['os'].append(atest) + +for target in sorted(TEST_NAMES, reverse=(env['TEST_ORDER']=='reverse')): + # Don't skip ignored tests when a single test was explicitly requested + if skip_ignored_tests and len(TEST_NAMES) > 1: + if target in BLACKLIST['ignore']: + SKIPPED_TESTS['ignore'] += 1 + # print_safe('skipping test %s -- found in black list' % (target)) + continue + if target in BLACKLIST['os']: + SKIPPED_TESTS['os'] += 1 + # print_safe('skipping test %s -- found in black list' % (target)) + continue + + if not os.path.exists(os.path.abspath(os.path.join('testsuite', target, 'README'))): + print_safe('skipping test %s -- missing README' % target) + SKIPPED_TESTS['other'] += 1 + continue + + test_target = Test.CreateTest(target, locals()).prepare_test(target, test_env) + if test_target: + TEST_TARGETS.append(test_target) + else: + SKIPPED_TESTS['other'] += 1 + + +## create top-level makeweb html +if len(TEST_TARGETS) > 0: + BUILD_TARGETS.append('testsuite') + TESTSUITE = test_env.Testsuite(os.path.join(test_env.Dir('.').abspath, 'index.html'), TEST_TARGETS, + PRINT_CMD_LINE_FUNC = lambda a, b, c, d : None, ## silence the builder + chdir = 0 + ) + test_env.AlwaysBuild(TESTSUITE) + +Return('TESTSUITE') diff --git a/testsuite/common/Makefile b/testsuite/common/Makefile new file mode 100755 index 0000000000..6c38dc5bd7 --- /dev/null +++ b/testsuite/common/Makefile @@ -0,0 +1,51 @@ +# +# Generic Makefile to automatically build shaders, procedural DSO's, etc. +# Only one source C file (or CPP) is allowed per test. The caller should +# cd into the data directory for that test: +# cd data +# make +# cd .. +# + +SHARED = -shared +LIBEXT = .so +ifeq ($(OSTYPE), darwin) + SHARED = -dynamiclib + LIBEXT = .so + #LIBEXT = .dylib +endif + +SOURCE = $(wildcard *.c *.cpp) +MAKEFILE = ../../common/Makefile +ARNOLDSDK = ${PROJDIR}/core +BASENAME = $(basename $(SOURCE)) +TARGET = $(addsuffix $(LIBEXT), $(BASENAME)) +OBJECTS = $(addsuffix .o, $(BASENAME)) + +LIBS = -L$(LD_LIBRARY_PATH) -lai +CC = gcc +CXX = g++ +CFLAGS = -D_LINUX -I$(ARNOLDSDK)/include +ifeq ($(MACHTYPE), x86_64) + CFLAGS += -D_64BIT -fPIC +endif +CXXFLAGS = $(CFLAGS) + +default: $(TARGET) + +all : $(TARGET) + +$(TARGET) : $(OBJECTS) + $(CC) $(CFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS) $(SHARED) + +debug : CFLAGS += -g -D_DEBUG +debug : $(TARGET) + +.PHONY : clean +clean : + @-rm $(TARGET) $(OBJECTS) core* 2> /dev/null + +.PHONY : remake +remake : + make -f $(MAKEFILE) clean ; make -f $(MAKEFILE) + diff --git a/testsuite/common/README.template b/testsuite/common/README.template new file mode 100755 index 0000000000..debfd8d42c --- /dev/null +++ b/testsuite/common/README.template @@ -0,0 +1,13 @@ +TODO #1: write a one-line description here + +TODO #2: optional, multi-line description here + +TODO #3: add to the testsuite/groups file if needed (node entry groups are automatic) + +TODO #4: make sure output driver uses "color_space sRGB", and there are no unused/unnecessary/big nodes + +See trac#**** + +author: **** **** + +PARAMS: {} # Remove this line if no custom params are needed diff --git a/testsuite/common/makeweb b/testsuite/common/makeweb new file mode 100755 index 0000000000..0a8982b69f --- /dev/null +++ b/testsuite/common/makeweb @@ -0,0 +1,268 @@ +#!/bin/sh +# +# this script assumes the user is running from inside the 'testsuite/common' +# directory +# + +# +# let's dump everything in this directory. This script does *not* clean-up the directory +# prior to copying everything so we might get old and stale files in there. +# +WEBDIR=$WEBDIR +PROJDIR=$PROJDIR +BANNER=http://www.spimageworks.com/people/arnold/arnold_banner.png +ARCH=$ARCH + +# +# set file-creation mask so that everyone can overwrite +# this run at a later date +# +umask 0 + +# print help message +Help() +{ + /bin/echo "Arnold makeweb script" + /bin/echo "Builds an HTML page with the results of the last run of the testsuite" + /bin/echo "Usage: `basename $0` [OPTIONS]" + /bin/echo "" + /bin/echo "Available options:" + /bin/echo " -f fast mode, don't rebuild/copy the images, just HTML" + /bin/echo " -q quiet mode, supress verbosity" + /bin/echo " -t specify target directory (defaults to $WEBDIR)" + exit 0 +} + +ParseCommandline() +{ + FAST=0 + QUIET=0 + while [ "$#" -gt "0" ] + do + if [ $1 = "help" ]; then + Help + fi + if [ $1 = "-f" ]; then + FAST=1 + fi + if [ $1 = "-q" ]; then + QUIET=1 + fi + if [ $1 = "-t" ]; then + shift + WEBDIR=$1 + /bin/echo "Using ${WEBDIR} ..." + fi + shift + done +} + + +##### EXECUTION STARTS HERE ########################################################## + +ParseCommandline $@ + +# +# this is the image resolution of the test images +# +SIZE=width=160 height=120 +# +# this is the image rez of the thumbnails +# (other useful resolutions: 80x60, 60x45, 40x30) +# +HSIZE=width=60 height=45 + +KICK=$KICK +DIFFTIFF=$DIFFTIFF +TIFF2JPEG=$TIFF2JPEG + +# +# create an Arnold version string +# +ARNOLD="Arnold-`$KICK -av`-$ARCH" +FILETYPES=".ass .c* Makefile" +RED="bgcolor=#ffa0a0" +GREY="bgcolor=#ececec" + +if [ ! -d $WEBDIR ]; then + mkdir $WEBDIR +fi + +cd $PROJDIR/testsuite +/bin/echo "" > $WEBDIR/index.html +/bin/echo "" >> $WEBDIR/index.html +/bin/echo "" >> $WEBDIR/index.html +/bin/echo "$ARNOLD testsuite" >> $WEBDIR/index.html +/bin/echo "" >> $WEBDIR/index.html +/bin/echo " " >> $WEBDIR/index.html + +/bin/echo "" >> $WEBDIR/index.html +/bin/echo "" >> $WEBDIR/index.html +/bin/echo "" >> $WEBDIR/index.html +/bin/echo "

testsuite results

" >> $WEBDIR/index.html +/bin/echo "
"                                                 >> $WEBDIR/index.html
+/bin/echo "version : $ARNOLD"                                     >> $WEBDIR/index.html
+/bin/echo "date    : `date`"                                      >> $WEBDIR/index.html
+/bin/echo "user    : $USER"                                       >> $WEBDIR/index.html
+/bin/echo "script  : `basename $0`"                               >> $WEBDIR/index.html
+/bin/echo "tests   : `ls -d test_0* | wc -l`"                     >> $WEBDIR/index.html
+TESTS=$(ls -d test*)
+NUM_FAILED=0
+for i in $TESTS
+do
+   if [ -f ${i}/FAILED ]; then
+      NUM_FAILED=$((NUM_FAILED + 1))
+   fi
+done
+/bin/echo "failed  : $NUM_FAILED"                                 >> $WEBDIR/index.html
+/bin/echo "
" >> $WEBDIR/index.html +/bin/echo "" >> $WEBDIR/index.html +/bin/echo "

" >> $WEBDIR/index.html +/bin/echo "" >> $WEBDIR/index.html +/bin/echo "" >> $WEBDIR/index.html +/bin/echo "" >> $WEBDIR/index.html +/bin/echo "" >> $WEBDIR/index.html +/bin/echo "" >> $WEBDIR/index.html +/bin/echo "" >> $WEBDIR/index.html +/bin/echo "" >> $WEBDIR/index.html +/bin/echo "" >> $WEBDIR/index.html + +TESTS=$(ls -d test*) +/bin/echo -n "processing $(/bin/echo $TESTS | wc -w) tests " +for i in $TESTS +do + if [ $QUIET -eq "0" ]; then + /bin/echo -n "." + fi + mkdir -p ${WEBDIR}/${i} + for j in $FILETYPES + do + cp $i/data/*${j} ${WEBDIR}/${i}/ 2>/dev/null + done + + FAILED=0 + COLOR=$GREY + STATUS=OK + if [ -f ${i}/FAILED ]; then + FAILED=1 + COLOR=$RED + STATUS=failed + fi + + /bin/echo "" >> $WEBDIR/index.html + + /bin/echo "" >> $WEBDIR/index.html + + /bin/echo "" >> $WEBDIR/index.html + + if [ -f ${i}/ref/reference.tif ]; then + /bin/echo "" >> $WEBDIR/index.html + /bin/echo "" >> $WEBDIR/index.html + if [ $FAST -eq "0" ]; then + if [ -f ${i}/new/testrender.tif ]; then + $TIFF2JPEG $i/new/testrender.tif $WEBDIR/${i}/new.jpg + $TIFF2JPEG $i/ref/reference.tif $WEBDIR/${i}/ref.jpg + if [ $FAILED -eq "1" ]; then + $DIFFTIFF -s -f $WEBDIR/${i}/diff.tif $i/new/testrender.tif $i/ref/reference.tif >/dev/null + $TIFF2JPEG $WEBDIR/${i}/diff.tif $WEBDIR/${i}/diff.jpg + rm $WEBDIR/${i}/diff.tif + fi + fi + fi + else + /bin/echo "" >> $WEBDIR/index.html + /bin/echo "" >> $WEBDIR/index.html + fi + + /bin/echo "" >> $WEBDIR/index.html + /bin/echo "" >> $WEBDIR/index.html + + TESTPAGE=$WEBDIR/${i}/test.html + /bin/echo "" > $TESTPAGE + /bin/echo "" >> $TESTPAGE + /bin/echo "$ARNOLD ${i}" >> $TESTPAGE + /bin/echo " " >> $TESTPAGE + /bin/echo "" >> $TESTPAGE + /bin/echo "" >> $TESTPAGE + /bin/echo "
testdescriptionnewref
" >> $WEBDIR/index.html + /bin/echo -n "" >> $WEBDIR/index.html + /bin/echo "
 $i 
" >> $WEBDIR/index.html + /bin/echo "
" >> $WEBDIR/index.html + /bin/echo " " >> $WEBDIR/index.html + head -1 $i/README >> $WEBDIR/index.html + /bin/echo " " >> $WEBDIR/index.html + /bin/echo "" >> $WEBDIR/index.html + /bin/echo -n "" >> $WEBDIR/index.html + /bin/echo "" >> $WEBDIR/index.html + /bin/echo "" >> $WEBDIR/index.html + /bin/echo -n "" >> $WEBDIR/index.html + /bin/echo "" >> $WEBDIR/index.html + /bin/echo "" >> $WEBDIR/index.html + /bin/echo "" >> $WEBDIR/index.html + /bin/echo "
" >> $WEBDIR/index.html + /bin/echo " 
no
 " >> $WEBDIR/index.html + /bin/echo "
" >> $WEBDIR/index.html + /bin/echo "
" >> $WEBDIR/index.html + /bin/echo "
" >> $WEBDIR/index.html + /bin/echo " 
image
 " >> $WEBDIR/index.html + /bin/echo "
" >> $WEBDIR/index.html + /bin/echo "
" >> $TESTPAGE + /bin/echo "" >> $TESTPAGE + /bin/echo "" >> $TESTPAGE + /bin/echo "" >> $TESTPAGE + /bin/echo "" >> $TESTPAGE + /bin/echo "" >> $TESTPAGE + /bin/echo "" >> $TESTPAGE + /bin/echo "" >> $TESTPAGE + /bin/echo "" >> $TESTPAGE + + /bin/echo "" >> $TESTPAGE + + /bin/echo "" >> $TESTPAGE + + /bin/echo "" >> $TESTPAGE + + /bin/echo "" >> $TESTPAGE + + /bin/echo "" >> $TESTPAGE + + /bin/echo "" >> $TESTPAGE + + /bin/echo "" >> $TESTPAGE + + /bin/echo "" >> $TESTPAGE + /bin/echo "
teststatusdescriptionnewrefdiff
" >> $TESTPAGE + /bin/echo "
 $i 
" >> $TESTPAGE + /bin/echo "
" >> $TESTPAGE + /bin/echo "
 $STATUS 
" >> $TESTPAGE + /bin/echo "
" >> $TESTPAGE + /bin/echo " " >> $TESTPAGE + /bin/echo "
"                                              >> $TESTPAGE
+   cat $i/README                                             >> $TESTPAGE
+   /bin/echo "
" >> $TESTPAGE + /bin/echo " " >> $TESTPAGE + /bin/echo "
" >> $TESTPAGE + /bin/echo "" >> $TESTPAGE + /bin/echo "" >> $TESTPAGE + /bin/echo "" >> $TESTPAGE + /bin/echo "" >> $TESTPAGE + if [ $FAILED -eq "1" ]; then + /bin/echo "" >> $TESTPAGE + else + /bin/echo " no difference " >> $TESTPAGE + fi + /bin/echo "
" >> $TESTPAGE + /bin/echo "link to files" >> $TESTPAGE + /bin/echo "" >> $TESTPAGE + /bin/echo "" >> $TESTPAGE + /bin/echo "" >> $TESTPAGE +done + +/bin/echo "" >> $WEBDIR/index.html +/bin/echo "
" >> $WEBDIR/index.html +/bin/echo "" >> $WEBDIR/index.html +/bin/echo "" >> $WEBDIR/index.html + +/bin/echo "" diff --git a/testsuite/common/rooftop_small.hdr b/testsuite/common/rooftop_small.hdr new file mode 100755 index 0000000000..bf53b4fb74 --- /dev/null +++ b/testsuite/common/rooftop_small.hdr @@ -0,0 +1,287 @@ +#?RADIANCE +FORMAT=32-bit_rle_rgbe + +-Y 150 +X 300 +,***+*+*+*+++*+*+++*+*+*++**+*+*+SRSSRRSTSRSTSTSTSTSTSTSTSTSTSRSRSRS,**)))***)*)*)*))*)*)*))**)*+*++**+*+ ,,,++,,+,+,+,+,,+*+*RSSRRSRSRQRSRQRSRRRSRRSTSTSTSTUTUTTUTUTUTSTSRSTSRSSSR   ,)()(()()()()()))(())()* )))**)*)*)**))*++*+*+*+,+,-,-,-,+++,,+,+,,,+,+*+**+*)**))**RQRQRRQRRQQRQ RRQQRRQRRQQRQRQRSRSSRSRSTSTUTUTTUTUVUVUUUVUVUUVUTTUUTTTUTUTSTSSSTTSTSRSRRRSSR   +,)()()()()()()))(()(())()*)**)*+**++*+,+,+,-,---,-,-,-.-,-, +--,,--,,,+, +,,,++,,,+*+*)*))**)RQRQQRQRQRQPQPQRQRQQQRQRQRSRSRRSTSST UUTTTUTTTUVVUVUVUVVVUUUVWVWWWVVVWVWVWVVWWWVUUVUVVUTUTUTTTSTSRSRRRSR"  ,)(())('('(((''(''((''('('('()()))()())*)))*+*+**+++*+,-,- +..--..--.-.-.-..---.-,-,+***+++*))*))*)RQRQPQPPPQPPPQQPQPQQQPPQPPQPQPQRQRQQQRSRSTTTSTUVUVWWWVWXWWWXWXWXXXWXWVUVVUVUTSSTSRSSRSRSRRR +     $,(())('''((('(''('((('()(())(()())*)*+*+,-,-.--.--././0///00/0//././/.//./.-,--,,-,+++,,+ +*+***)))**)()( RRQQRRQQRQPQQPQQPPQPQPQPQPPQPQPQQPQRSTSTUVWWVWXWXYZYZYYYZZZYXWVUVUTUTSSSTSR    +,('( ''(('(('''&'&'&'&'&&'&&'&&''&&''&'&'('''()()()(()*)*++**+,+,-./0110100101110010110010/.//..//.-,,,--,++,+*)* ))*)())()(RQQRRRQ PPQPQQPPPQPQP QPPPQPPPQPQPQPQQPPQPPQRQQQRSRSTUTUVWXYZ[Z[[[ZZ[Z[ZZZ[[[ZYZZYXXXWXWVUVUVUTSSTSRSSRQRRR ,(''(''('&'&'&&''&&&'&'&&''&&&'&&&''&&'''&'&'(''((('( ''()))((()*+,++,-././//0//01012212321211210/.//.-..-,+,+*+++***+*) ())((('((RQ +PQPPQPPQQQPQPQPQPQP QQQPPPQQQPPQRRQQRSTUVUVWXWXYZ[Z[\]\]\]\]\[\[ZYXWVUTTUTSR! +,('&&''&'&&'&&&'&&'&&&'&'&''&'&'&'()))(() ())*))**)*+*+,-.-...-../0 110111211234443343433432232112110010/./.-,+*+*)*)((())(QRRQRQPQPQQQPPQPPQPQPPQQP QPPPQPQQPQRQRQQRSTUVWXYXYYYZ[\]^]^___^___^_^_^]\]\[ZYYYXYXWWWVWWVUTSRSR$ ,'(('&'&%&'&'&&'&'('()()*+,-./0122232223454565 665655566543223210/./.---.--,-,-,,,+++,+*)*)(RQPQPQPQQPQRSTUTTUVUVWXXYYXYZ[\]^__^_`a`a`aa`a`_^__^]\[ZYXWVUTSR  *! ,'('&'&&'&&'&%&%&%&'&'('''()*+,-./01234356767665665433323322211100100/0/.-,+*++*)*)))())())(''((''RQRQRQQRQPQQPQPPQPQRRQQRSTUVWWVWXYZ[\]^_`abccbbbcbaabaaa`_^^_^^^] \\\[[[ZZ[ZZYXWVUTSRS   + ,''('&%&%&&%&%&%&'&&'&'&'((('())()*)))*)*+, --,---.../0/0123 44455445567898889:999:9:989:99988878876543210/.-,,,+,+*)***) ()(('(('(RQRQRQRRQRSTUV +WWXWXXXYYYZ[\\[\]^_```aaabcdcdedeedefeeefededcb abaaa`a``_^]]]\\\[ZYXWVUTUTSTTSR + ,('&%&%&&&%&'('())()**)*+++,,,-,-./0111222333444555665677789:;;::;< +;<<<;;<;;:;::99:999876543211100/0/.-,+,,+,+*)()(SRSRRRQQQRQRQRQQRQQRRRQQQRQRQRQQQRQRQRQRQRSTUVWXYYYZZZ[[[\\\]]]^^^___```aaabbbcdefefffggfghggghgfeefedcba`_^^^]]]\[ZYXWVUTS J,('&'''&%&%&%&'&'(''(('()()*+,-./01234 555666777899:::;;<=>===>=<=>==>=>===<;:::9898765431 000/00/./.-,+*))*)))(())'(((TSRSSSRSRRRSRRSSSTSTUVWXXXYYYZZZ[[[\\] ^^^__```aaabcdddeefffghhhihiiijkkjjkjkkkjjkkjjjijjijihgfeeedddcccbbbaaa``___^^^]\\\[[[ZYXWXWVUT (% + +,('&'&'&'&'&'&&'('''()*)*++,++,,-./0112223345666787999:9::;;;<<===>?@AA@A@AA@A@ +???>??>===<;;::99987656554443210/.-..-,+*)))()(()(TSTTSTSRSRRSRSRSRSTUV0WWWXWXXYYYZZ[[[\\\]]]^^^__``aaabbcccddeeeffggghhijklmnnmnnmlkjihhgggffeededdcccbbaa`__^^^]\\\[[[ZYXWVUTTUUT + 8 ) +,(''('&'&'&'''&'&'&&&'&'&'&'('''()*+,--.-..///000111222334445656788999:::< ==>?>???@@@ABCDCDBBCDCBBA@?>>=>==< ;;:::9888766655444321000///.--,,-,+*)()(UTUUTUUUTUTSTSTSTSTTSTUVWXYZ,[[[\]]]^^^_```aaabccdddeefggghhiiijjjkkllmmmnopq +pqpppqqqppo3nnnmmmlllkkkjjjihhhgggfffeedddccbbaaa```___^^^]]\\\[ZYXWVU!„ą ,('('('&&'&''&&'&'''&'&''&&'&&''&'&&&'&'&''&&'''&&'&'()((()*+,,,---.+///000111233344455667888999:;;;<<<>>>?@?@@ABCDEFFEF#GFFEFFEGHHGDDECCCBBBCBABA@@@???>>==<;:::9988877666554443321100/.-,+*)))()))(UVVVUVUUVUVUUUVUTTUTUAVUVUVVVWWWXWXXXYYYZZZ[[\\]]]^^___`aabbcccddeefggghhiijjkklllmnnnopqrstutttuttsuvutsssrrrqqqpoonnnmmmllkkjjiihhhggffeeeddcbaa```_^^]\\\[[[ZYXWVUVV / ÅńĆÅ + ,)('('('&'&'&'('())(()*)***+,--...//0211222334445567778999::;<<==>???@@AABBCDDEEEFGFGGHIHIJ IJIHJNLJHHHG FFFEEEDDDCBBA@??>>>==<<;;::9988877765443321000//0/.-,+*+*)WVWVWVWVWVWVVVWVUVVUTUTUVWVWWWX@YYYZZZ[[[\\]]^^___`aabbccddeeffgghiiijkkllmmnooopqqqrrsstttuvuvvwxww{{xwwwv;uutttsssrrrqpppoonnnmllkkjjiihhggffeedddccbbaa``___^^^]]\\\[ZYXWXWVVW +  + Ä ʅT,)))())('((''('('()*+,@---...///000112223444567788899::<<<==>?@@@AABCCCDEFFGGHIIJJJKJLKL MNMMMNNMMMPSOLK7JJJIIHHGFGFFEDDCBBAA@@??>>===<;;;:9998877765554433222110 ///...---,-,+,+*+*+*)XW XXWXXWXXWXWXXXWX +WXWWXWXWWXWVUVVUUVVUVWVVWWWXWXYZ=[[\\\]^^__``aabbccddeeffghhiijkklmmmnoopqqrrsstuuvvvwxxxyyzzz{|{~{z(yyxxwwvvvuuttsrrqqppoonnmmlkkjjihhhggffedcbbaa```__^^^]]]\\\[ZYXWXX   N҄= ,)*)(())('('('('( ''(('''(('('('(' ('('('('''(''()*)***+,---...//0-1223344556677899::;;===??@@ABBCDDEEFGHHHIJKKLM NNOPPQQQPQRQQUQPOONNMMLLKKKJIIHHGGFEEDCBCAAA@?>=<;;;::99887765554433221110/.-,+*+***)*)YYXXXYYYXYXXYXWXWVVWVWWVWX9YYYZZZ[[\\\]]]^^_```aabbcddeefgghiijjkllmnnoppqrrsttuuvvxyz{|||}~ ~}<|{{zzyxxxwvvuutssrqqpponnmllkkjjihhggffeeddccbbaaa``__^^^]]]\[ZYX AՅ؄׆„!,)*)(()()('(('(('()*+,-.../0,1122344555677899::;<<=>??@AABCCDEFGHHIJKLMMNOQQQRTSSTTUUTTVUEVUTUUTUTTSTSSRRQQPOONNLLKKJIIHGGFEEDCBBBAA@??>==<<;::99887766554333221000//...-,+*++* ZZYYYZYZZYZYZ[Z[Z[ZYXYYXYXWXYKZZZ[[[\\\]]^^__``aaabcddeefgghhijkklmmnoopqrrstuuvvwxyzz{|}~~C~~~}|{zzyyxwwvuttsrrqpponnmlkkkjiihhgffeeddccbaaa```___^^]\[ZY +GބC,*)))*)()()(()(() ())(())(()(()()*H++,+,,---...///000112344455768889::;<<=>?@@ACCCDEFGHHIKKLMNOPPRRSTTUVVVWXYZYZMYYYXXXWXWVVUUUTSSRQQPOONLKLJJIHGFFFEDDBAAA?@?===<;;99988766554433322111000///.-,,,+,+*[[[Z[\[\]\]\]\[ZYXYZ[D\\\]]^^___`aaabccddeffghiijkklmnnoppqrstuuvwxyzz{|}~E~~}||{zyxxwvuutssrqqoonmlllkjjihhggfeedcccbbaa`___^^^]\[ RE +,*+*))*)*)*)(())()()())()*)*+,---./F01112233445667889:;;<=>>?@ABCDDEFGHIJKLMNOOQRRSTUVVWYYZZ[[\\\]]]^^^__^_^]D\\\[ZYXXXWVUUTSRRQPONMLKKJIHGFEEDCBA@@@>>==<:::988776654433322111000/.-,+*\]]]\]^]]^]\[ZZ[ZYZZYZZZYZ[[Z[[\G]]^^^__```aabcccdeefgghijjklmmnopqqrstuvwwxyz{|}~O~}|{zzxxwvuutsrqpponnmlkkjiihhgffeddcccbbaaa```___^]\]\  G; +, +++*+++*+*)*)*)*)()*))*)*+,-D..///000122334456677899:;<=>>?@ABCDDFFGIJKLMNPQQSTTUVWYYZ[\\^^__`aaabcdcdeedIccbccbbaa`_`_]\[[ZYYXWVVTTSRQOONMLKJJHGFFEDCBA@?>>=<<;::988776544433212110/.-,+,,+,+]^^^]^_^^_^_`_`a`_^]\[\[\]]]^^^___``aabbccddeffghiijkllmnooqqrstuvwwxy{|}~~|{{zy(xwwvttsrqpponmllkjjihhgffeeedcccbbbaa```_^] +;P,+*++*++***+* ++++**+**++*+*)*)*)*+,-P..//00111223445667789::;<=>>?@ABCDFFGIIJLMNPPRSTUVWXYZ\]^_aaabcceeefgghghhijjijjih?gffeedcbba`_^^\[ZZYWWVUSSQPONNMKJIHFFDDCBA@?>>=<;::99877655433321100/.-,+_`_`aba`a`_^]\]\]\]^L___`aaabbbcdeeffgghijkklmnoopqrstuvwxyz{|}~L~}||{yxxvvtssrqponnmlkjjihhggffeeddcba`_^___ąK`, ,,,+,++,,++,+,+*)**)*+,-C..///00112234445667889:;<<=>?@ACCDEGHIJKLNOPRSTUVXZZ[\^_`acdeefgiij56667778765=44gffedcba`^^]\[ZXXWUTSRPPNMLKIHGFEDCBA??>=<<;:9987765543332210/.-,`abcdddcdcba`_^]^_H```aaabbccddeefghhiijklmnnopqrstuvwxyz{|}~PPPQRSRRSRQPEOO}}{zyxwvutsrqponmmlkkjihhggffeeddcccbbaba`ńƄ ɄȅH?,,+,+,,++,+*++*+,+,-,-./H0011233445667789::;<=>?@ABCDEGHIJLLNPQRTUVWYZ[]]`abceff3i556677788999:99:9I888777655443gfecba__]\[ZYWVUTSQPOMLKJHGFEDCAA?>=<<;::87766554433222111000/./.-,-,,bcdedefefefedcba`_`aHbbbccddeeefgghiijjllmnoppqrttuwwyz{|}~OPQQRRSSTTTUVWVUHTTTSSRQQQPOO~}|{zyxvutsrqponnllkjjihhggffeedddcccbabbab ƇɅʂ˅̄ɄƄĂąA>,-,-,,,-,,-,-,-,,-,+++,++,+,-.J//000112333545667889:;<==>?@ABDEGHIJKMNOQRTUWXZ[\^_abdef4455667899:::;;<<<=>=>===?@ABCDEGIJKMNOQSTUWXY\]^`bc2334567789:;;;<=>>?>?@@ABSA@@A@@???>>==<;;:988876554332cba^^\ZYWVTSRPOMLJIHFEDCA@?>=<;::9987655543332221110/0/.-..efghijkjijihgfedcbbcbcOdddeeeffgghhiijkklmnnopqrstuvwxyz|}~NOPQRRSTUUVWXYYZZ[\\]]^^^_O^^^]]]\\[[ZYYXXWVUUTSRQPPONM~}{zxwvutsrqponmllkkjiihhggfffeeedcde ̈́΂τЂх ԅՄ̄!ĄAFŅĆ,.-.-./././//.-.-,-,-.N//000111222445667789:::<==>?ABBCEFHIKLNPQRTUWYZ[]_ab2234556799:;<==??@@@BBBCDDEFEFNEEEDDDCCBBA@@??>==<;:98876554321ba_]\ZYWVUSQPNMLJHGEDBB@??><;;:98876665444333210/../.ghijklmmllmmmlkjiiihihg fffeefeeedePfffgghhhiijjkllmnoopqrstuvwxzz|}NOPQRSTUUWXXYZ[\]]^_``aabbbcccdcHbbbaa``__^]\\[ZYXWWUTSSRQPONM~}{zywvutsrqponnmllkjjiiihgfefgfׅ ҅'ĄIF˄ ƅ ǀ,././0//0/0/ .///.//./.-,-,,-./M000112223445666889::;<=>?@ABCEFHIJLNOQSTUWXZ\^_a1223456799:;==>?@ABBDEDFFGGHHIJQIIIHHHGGFFEDCCBAA@??==<;:9876543221`_^\ZYXVTSQOMLJIGFECBA@?>=<;:9988766554433322210/.hijklmnooonoononmlkjihgfefefghFiijjklllmnoppqrstuvwxz{|}~NOPQRSTUVWXYZ[\]^_`abcddeeffghihihIgggffeedccba``_^]\[ZYXWVUTSRQPOMM~}{zxwvutsrqpponmmllkkjjihgfggfgggh\ɅȅTC̄ʄ̀,/./0//0 1100010110/0/0//0/.-./R0001122234455667889:;;<=>?@ACDEFHJKMNPQSUVXZ[]^0122355689:;<=>?@BBDDEFGHIJJKKLLMMMNSMMLLLKKJJIHHFEEDDBAA@?>=;;:8865432210_]\ZXWUSRPNMKIHGEDCA@?>=<<;:98877766554433322210///00//jklmnonoopqpqpponmlkjihgShhhiijjjkkllmmnoopqrstuvwxyz|}MNOPQRTUVWXZ[\]^_`bbceffghiijkkkllmmmnmlLkkjiihgfeedcaa`_^][ZYXWVTSRQPONML~|{zywvuusrqqpoonnmlllkkkjjjihihij-"Ѕ̇ʇLDτ΃̈́Ӏ,0/01001 +22121122121210/0/.//./0/001U2233445667789::;;=>>?@BCDFHIJLNOQSTVWYZ]/0012456789:<=>?@BCDEFGHIJKLMNNOPQQRRRSSTTSSTSKRRQPPPONMLKJIIHGFEDCB@?>=<;:9765533100^][YWVTSQOMLJIHFDCBA??>=<;::99887666543322210lmnopoopppqrststsrqponmmmlllkjihihiiihiQjjjkkklmmmnooppqrstuuvxyz{}~LMNOQRSTUWXY[\]^`abcdeghijjllmnopqqqrrrsrNqqpponnmkkjihgfedcb`_^\[ZYXVUTSRPONML~}{zyxwutssrqqpoonnnmmmlllkjkjkl#ބ̈́ +̄̀$Єυ؀,01100121123222332232223210//0/./01Q22333455668899:;;<=>>@@CCDFHJKMNORSUWY[[./013346789;<=?@ABCEFGHJKLMOOQQRSUVVWWWXXYXTWWVVUUTSRQPONLLJIIGFEDBA@?==;:876543210/.\ZYWTSQOMLKIHFECBA@??==<;:998877666554443332101nopqrstuvutsrqqqpponmlllkkjkjSkkkllmmmnoooppqrssttvvwxz{|~LMNOQRSUVWYZ\]^`abdefghjklmnopqrstuvvwwxxyxNwwwuutsrrqonmlkjihgedca`_]\ZYXWUTSRPONMLK~}{zyxwvuttsrrqpppoonnnmlmmlm(҄΄LIքӇӅ݀,12112323434321210//000/0/01V222333445667889:;;<=>>?@ABDEFHJLMNQSTVXY[./012356789;<=?@ACDFGHJKLNOQRSTVVWYZ[\\]]]^^^_W^^]^]\\[ZYYXWVUSSQOOMLKIHGFDCB@?>=;9876543210/.ZYWUSRPNMLJHGFDCBA@?>=<<;:::887776665444321pqrstuvwvwwxyxwvuututttsssrrrqqponmlmmnnnooppqqrrsstuvwwxz{|~LMOPQRTUVXZ[\^_abcefhijlmopqrstvwwxz{||}}~~~~}||{yyxwvtsrqpomlkihgedba_^][ZYWUT*SRQPNMLK~}|{zxxwvuttsrrrqqpponono+ԅцTF؄ֆՄ း, 232223322345665665654321 001000100123334456667789::;;<=>?@@BCDFGIKLNPQTVVX-./012356789;<=?@BCEGGIJLMOQRTUWXZ[]]^``abccdeeffeffededdccbba_^]\[YYWVUTRQOMLKJHFECBA@=<;/987653210/..ZXVUSRONLJIGFECCBA@?>=<<;::9888776654454323233rrrssstuuvvvwwwxyz{|||{{|{z yyyxxxwwwvvvu ttssrrrqqqpppononmnRoooppqqqrsssuuvwwxyz{|}KLMNPQRTUVXY[]^`bcdfgijlmoprsuvwyz{}~O~}{zyxvusrponlkihfeca`^][ZXWVTSRQONMLK~}|{zyxwwvuuttssrqpq -ل_c怶,44334434567676767776543332332111212Z33343345556677899:;;<=>??AABDEGHIKLOQRTVX,-/002346789:<>?@BDEGHJLMOQRTVXY[\^_abbeeghhijkllmXlmlkkjiihhfecba_^\[ZXWUTRPOMKJHGECB@?><;986543210/.-,WUTRPNMKIHFEDCBA@?>>==<;;:9988777665454343ttuuuvvwxy zz{{|{|||}~}~}~}|||{{{zyyyxxw vvvutttssrrrqpopRqqqrrrsstuuvwwxyyz{}~KLMNPQRTUWXZ[]^`bcefhjkmoprsuvxz|}~V}|zxwutrqomljhgecb`_][ZXWVTSRQONMLKJ~}}{zzyxwwvvuuutttsrsstt/ڋUC߃މ݄ބ뀳,56667667766776543232345566777899:;;<=>>@ABBCEFHIKMNPQSUV,-./01245689:<=?ABDEGIKLNPRTVXZ\]_`bdefhiklnooqrsttuutuvuttssrqpoomlkihfdca_]\ZYWUSQOMLJHFECB@0>=<:986543210.--,VTRQOMKJHGFEDCBAA??>>=<;;:9998876 555455545wxxyyyzz{ |||}}}~~~???@?~~~}}}|{zzyyyxxwwvvvuutsrqrrqrSssstuuuvvwwxyzz{|}~JLMNOQRSUVXZ[]_abdehiklnprsuwy{|~S~|{ywutrpnlkigecb`_][ZXWVTSRPONMLKJ~}|{zzyxxxwwwvvvuttutuvV +,678787665654343456667889::;;<=>?@@ABCDEGHIKMOPRT+,,-.01135578:;=>@BCEGIJLNPQUWY[]_acegiklnpqrtuvxz{{|}}~~~~}}{zyyxvutrpnlkhgfdb`^\ZXVTRPMLJHFEC7A@>=;987643210/--,+URQOMLJIHFFDCBBA@@?>=<<<;:::9988877765yyzz{{{||}}}~~~@A@ABABABBA@~~}}}|||{zzyyyxxwwvvvutstuRvvwwxxyyz{|}}IJKLNOPRSUVXY[]_abdfgikmoqsuvx{}P}{ywusqomkigedb`_][ZXWUTSQPONMKJI~~}|{{{zyyyxwvwxxxy.",787788765454556667677899::;<=>>?@ABCCEFGIKLMOQS*+,-./01245689;<>?ACEGHKLNPRUXZ\^`cegikmoqtvwy{|~}|yxvtrpnmjhgda`^[YVT;RPNLJHFDCA?=<:98654310/.-,+*SQPOMKJHGFEDCBBA@??>>=<<<;:::99876|||}}~~@@@ABC DCCCDDCCDCDCBA@@@~~}}||{{zzyyxwvwxxyyz{{|}}~IJKLMNPQSTVWY[\^`bdegikmortvxz|~~|zxvsqomkigecb`^(][YXVUTRQPNMLKJI~}}}||{{zyzyz{!$ ,88899987656678899::;<=>??@ABCCEFGIJKLNPQ)*+,-./1234678:;=?@BDFHJLNPSVWZ]_bdfhjmpqtwx{~|zwutqnljgfca^\YWURPNKJ4GECB@>=;:8764320/.-,+*)RQOMKJIHGFEEDBAA@@?>>=<<<;;;:9898~~@@ABCDEDCBA@@~~}}||{{{zzzyxxxwxUyyyzzz{{|}}~IJKLMNOQRTUWXZ\^_acegikmoqtvx{}S}zxvtqomkigeca`^\ZYWVUSQPONMLKJI~~~}}|{|{|}}~0ǀ,:  898789:T;;<=>?@ABCDEFGHJKLMN())*+,./01235679;<>@ACEGHKNORUXZ\_begiloqsvy{~W}{xwtqolifdb^\YWUQPMJIGECA@><:9764321/.-,+**)QPNLKIIHFFEDCCBA@@?>>>==<<;:9:ABCD EEEFFFGEBGIHGFEDCBA @@~~~}}||{zU{{|||}}~HHIJLMNOPRSUVXY[]_acdfhjloqtvx{}Q}{xvsqomkigeba_]\ZXWUTRQPNMLKJIH~"TN¿Ѐ, ! ! 98989::;;;<==>??@BCDDFGHIJKM''()*+,-./0124568:;=?ABDFIJLNQTWY\_behkmprux{~|yvspmjgda_\YV6TQNLJHFDB@><;98653210.-,++*)QONMLKJIHGFEDDCBAA@???>>>=<;BCDDDEDEEEFFFGGGHFIJCGJIHGFEDCBA ~~~}}}|}~~GHIIJKLNOPQSTVWXZ\^`bdehjlnpsuxz}}zxusqnl(jhedb`^][YXVUSQPONMLKJIA+$¿#Հ, !"! " E!"!!!"!!"! !! ::999:;;<<<==>>?@ABCDEFGHHIK&&'(()*+,./01235678:<=?ACEGIKNPSUX[^aegknqtwz}}zwtqmjfc`7^ZXTROMKHFDB@>=;:8764210/.-,+*)(PNNLLKJIHGFEDCCBBAA@@??>=<<CDEFGGGHHHIJJKJHKNyNKJIHGGGFFFEDC BBBAAFGHIJJKLMNPQRTUVWYZ]_abegikmortwy|¿|ywtr+omkifdb`_][ZXWUTRQPOMLKKJHABC.ߜ c¾~,  !"###""#"""##""#!hO"#"""#"! ;<[==>>???@ABCDDFGGHI%%&''()*+,-./01246789;=?@BDFHKMNQUXZ]`dfjnptx{]^_`aaabbcTbba``^~zwtplieb_\YVSQNLIHECA?=<:97643200.-,+*))(POMLLKJHHHFFEDDCB!   EEEFFFGGGHIJ OQPNLLJNMNMOhOMLKJIIIHHHGGGFFEEEDDDCCCBBBAXFFGHIIJKLMNOPRSUVXYZ[]_bdehjlnpsux{~mnopqqqrrsSrrqponÿ}{xusqolifdcb`^\[YXVTSRPONMLKJIHCBCCDE"TE,! !"# $B=!!#$%$$$#$")#$$#$#"!"! =>???@AABCDEEFG$%%%&''((**+,-//0234679:<>?ACEGIKNPSVY[_behlosw{^_acdefhijkkklllkkjihfecb`_~zvrnkgd2`]ZWUROMJHECB@><;98654210/-,++*))(''ML&%%$$$###"""! ! ! FGGGHHHIIJKL JRkZEMTSNPOOP QJSOPOOPONOONNNMLKKKJJIIH GGGFFEEEDDDCCBREFFGGHIJJKLMNOPQSTVWYZ\]_`cegikmprtwy|npqstuvwxyyzz{Izyxwvtsrqo¿|yvtromjhfdca_][ZXWUTRQPOMLKJJIHHGGFEDEDDDEDEEEFHFF߈G~,!!!"!"#$$$"$&D٪C#$%&%&%&%$#"""!"! [ ??@AAABBCDE##$$%%&&&'(()*+,-./01245689;=?@BDFHJLOQTWZ]`dhjnrvy^`bdfhklnpqrsuWvvuttsqomlihfca_}yuqlheb^[YURPMKIFDB@>=;98753210.--,+**)(('''&&%%%$$$###"!"!!"!" ;"!)HHIIJJJKKKLLMMMNNHLSqQQ]osGUWTRQRRTJCwNSRQPONNNMMMLLLKKJJJIIHHHGGFEDCUEEFFFGGHHIJKKLMNOPQRTUVXY[]^`bdfhjlnqsux{~oqstvxz|}~H~|zywusqo}zxuspnligecb`^\[YWVTSRQONMLKJJIIIHGFGFGHEJG4k˄#-LD +ᐋ}~~€ր,#""#$%&#%IǹC#%'&&&(&'&'&''&%$#"! !""###$$%&&&'(()**+--./0234578:;=?ABDFIKMORUX\_behlptw}^abdgjlnqsvwy{}~}|zxvtrpnkifdb{vrnigc_(\YVSQNKIGEC@?=;:9754310/.-,++**)((('''&&%$$$##"#"$#"I:$ LJJKKLLMMMNNOQHOzF^a\O>]]lKWYUSUNI_LVTSRQPOONNNMMMLLKKJJIIIHHGGGFFFEDEQFFFGGHHHIIJKLLMNOPQRSTVWYZ\]_aceghkmoqtvy|oqsuwz{~H~|zwusq~{xvtqnljhfdb`^][ZXWUTRQPONMLKKJIHIGGHHKJKIKF~M4 &$1$)#NDÿᕓ}~~~~~Ԁ~,@$%$%&&&'''C۱ԯƺʜF&'(+*('&%$#"!"!"#Q$$%%&&'(())*+,-..01234579:;=?ACEGIKNQSVY\_cgjnqv{~_behjmpsuxz|f~|zwtqolifdb|wtokgd`]ZWTQOLJGECA?=<:8764320//.-,++**))((('''&&&%%%$$.5&$$#05/#A$5:)MPLMMNNOOOPQQQRQTt^ZJ`W`c_SD/]vS\[W]KTXWVUTSSSRRRQQQPPOOONNMMLLKKJJJIIHGFGGGHHHIIJJKKLMMNOPQRSTUWXY[\^`bcegiknpruwz}pruwz|~|zwusp!|ywtromkigeca_^\ZYWVTSRQPONMLLLKJIZnNKKHbk]KNfx+䒙/!$**) ,̚=1#Ŀ Ŕ}~~~ŀ },eR;'%&')J՚ݺּ˧OH*+)*)*)('&%$#"#U$$$%%%&''(())*++,../01235679:<=?ACEGILOQTX[]aehlptx}acfhlpsvx|g}zwtqnkhe~yuqmheb^[XUROLJGECA?=<:97653210/.-,,++**)))((('''&&&'=iF@:"&5Q]>77-~I)|RORPQQQSSRSSRYTNaBi]gQTd_g[B/uXZ[}SXYXYXXXWVVVUUUTTTSSSRRQQPPOONNMMLLLKKJIHIIIJJJKKLMMNOOPQRSTUWXYZ\]_acefhjlnqsvy{~psvx{~~{xvsľ|zwurpnljgedb`^][YXVUTSRQPONNMLKKNx|vGNemrU|0Wٛ!+%(&&(+ VBC/Ŀɝȁ͂ﺼ}~ }~~~~~~À +}~~}}~,)mC&:$''(H')(**'ƪڃ¯N*+*)*)('&%$##$#$%%&&&''(()**++,-../01345689;<>@ACEGJLORUX\_cfjmpvzadfjmptx||yvspmig{wrAmjfb_\XUROLJHFDA@><;986542100/.--,,+***)))((('('(3I1$'/6B+(‹NuLNORPTRX[IlOlLDUR<;987543210//.--,,++***)H&)(IY?K)3nKg+yKy~iY=vIDQSmOX3OSZ_O;W`]^]#\\\[[ZZYYYXXWWVVUUTSSRRRQQPPOONNNMMLKLRMMMNNOOPPQRRSTUVWXZ[\^_`bdfhjknpruwz}rux|I|yv½~{xvsqnljhfdca_^\[YXVUTSRRQQPONPJRNutSc|2Ce`ߣr9#.>' 7)31 %½򃓌ʘhZ6{{|}~~~}}|{{{~~~~~~~||}~~|}~|{|{,-{:HcaWJMǞ⼋ǃקO0../.-,+*)('&'((()**++,--../002245689:<=?ACEGILNRTXZ^aeilquy~gknrvy~zvsoküz@uqlhd`]ZWTPNKHFDB@>=;:9765432100/..---,++*))*@L<,Q_VPJy-鞭h‚gM|MGo\N>GO:IRaHE^FRV]\@b___`a`_!^^]]\\\[[ZZYYXXWVVUUTTSSRRQQQPPOONMNOOPPPQRRSTUUVWXY[\]_`bceghjloqsvx|~ux{~}zwľ~{yvtqomkigecb`^][ZYWVUTSSSRQQQPPONPwnW˰գ9! &+69C,&!,2*㧠&JɄE##F證6\%{~~~|~}|}}|{||{|~~~~~~~|{{|}~~|{||{{|,/䈖e`_?wMW𛲵䓽+,010010/.-,+*)('()**++,--.//002234578:;<>?ACEHJLORUY\_cfkosx|fjnrvz~|xtqnzw>rnifa^ZWTQNLIGEBA?><;987554321000///./,..++-4upo{̐-ِal-+qicXNhH=JbbZuJnBTQ[Pp_edccdc%bbbaa``__^^^]]\\[[ZZYXXWWVUUTTTSRRRQQPOPQQQRRSTTUVWWYYZ\]^`abdfgikmoqtwy|twz~Ŀ~{xſ={yvtromkigfdba_]\ZYXWVUUUTTTUUTWXXVRQW]ȅȩډelݍiĻV%  =!'&$+$m¿b!%Y&  {{|{|~~~}{z}~{|{|{{||~~|}}~~|{|{|{|,.Öiz]}⛾˥ԀךƋ~-.23212221110/.-,+*)())()*++,,--../0012335678:;=?ABDFIKNPSVY]`dhlptx~jnrvz~zwspſ?}xsokfb^ZWTQNLJGECA@>=;:97655432211101Ui30*:Kpyj-毮Xpsd5oU?ACEGILNQTWZ]`dhlpuz~lqty~~~}zws@}xtokgc_\YUROMJHFDB@?=<;:987654433322VӆN.EΛOaSGԁ҅-u{ˎxYkjRUnsnvWbPG?jlDW]``jih(ggffeeeddccbba``_^^]]\[[ZZYYXXWWVVUUUTTTSTSTQUUUVVVWXXYZ[\]^_`bcefgikmoqsvx{~w{hƿ~{ƿ}zwusqomkigedba_^\[ZYYXYYYZY[XcV{շ՝Йk0&);U(!3( +  *%G) (!$#<+PwxyhxwĽ¿@C͔s\7%_i {z{||{zzz{{{z{|{|||{||}}||{}~}z~|{|{{{z{zz{z{{||{|,0ƑಡΌϷ𡵠ƷƬ3776543210//./.-,V---...//0112334556789;<>@ACEGILORTXZ^aeimpvzrw|h~zûzuqmhd`\ZWSPNLIGECB@>=<;:98776655434H,@tÃᎬņ/fMƐmAeeekJw獢DW]ROQPG=k}MGrklk%jjjiihhggfffeedccbaa`__^]]\\[[ZZYYXXXWVWWWXXYYZ[[\]^_`abdfghjlmoqtvy{~|üƿ}{xutqomljhfdca`^]\[\\\[`h=sSqqaZw\lp~v/':G&sZO  + 7 + &#:$)vy{|}~|zxĿ@BDEHJLORUX[^bfimqv{tyƿ|ż>{vqmiea^ZWUROMKIGDCA@?=<;:998876665ՀsfYŧiתCh/ߒeqq~kvϕuK\SOPQNKOE:9`dpnml%kkjjiihhggffeddcbba``__^^]\\\[[ZZZYYYXYYYZ[Z[\]]^_`abcefhijlnprtvy{~}ƿƿ}{yvtrpnljigecb`_^]^=Ltc奥9}IlGg>)N22g )  + ;, &U&swz|}{wuž¾; +(f 55  {zxz{z{zzz{|{}~~{x|}}{{{zzz|{{|{|{zzz,-;ɸ֫Ą̃tއڪ;:98765433322210/011223355567899:;==?ABDFHJLORUX[_bejnrw|v{º~ƽ@|xsnjfc_[YVTQNLJHFECA@?>=<;::99887߸Tْƿ0_]_ZR_XRNGgUeKP8:tBfؐQH_TRPMPKRSX@alqopo'nnmmlllkkjihhggfeedccbbaa``_^^^]]\\\[[[Z[\\]Z]__`aabcefghjkmnqrtwy|~}}ſ<~{yvtrqomkigfdba`___^__``_a_=DY}졚iTaf@FTXY[[\^[5 $$0 #F + 'X#ptx|~{xupm¼¾:T +4E2*#~} ||{z|{|{{|{z{}􀔁~|{||}}}~,/‡jaν4?=<;:::99988877666555443211212223344567789::;<=>?@BCEGIKMOSVY\_cgkotx}|Ż~C}xtojgd`\ZWURPOMJHFEDBA?>==<;;::9I,KLJJJHIJJG>:T6G:7@etLQ\zubURRTRNUWLz_urs,rrrqqppooonmmllkjjihgggfedddcbbbaa`___^^^]]]\]]]^^_`]_abbcdefghijlmoqsuwy|~~ž@~{ywusqomkjhfdcbaa```aabacdCJIB?ijx>@EHIFCHIHDFGHG\.  %(?򑵱mqtx|{wsplľ~6V ""&~ }}}|y{{{||~~􀒁~,2ӛijNC?@@?>?>>>= +<<<;;;::998765434555667899:;;<=>?@ABCEFHJLNQSWZ]`cgkpty~{ŽB}xtolhea][XVTRPNKJHFEDBA@?>==;<;0GGGHHHJIHFILLMJKNFMKJPLKG>ce\ZecURSTQNRB:cs}uvu$tsssrrqqppoonmllkjjihhggffeeddccbbaa`_^_`ab_bddeefghijkmnpqsuwy|~{Ǿý~{ywusqomljhgedcbbabeAIHHGGJIJJHGDA@BFFCDEGG!")BZ~loswz`}zvqnjg|¼U ~~}|{z~~򀒁,.Θ٪³=CBA@@@?@@??>>===<<;;:::98765677889::;<<=>?@ABCDEFHJLNPRUWZ^adhlptyƿǾ2~yuqmiec_\ZWUSQOMKIHFECBA@?@eXQ 3GGFGGIFnFGIJLOIKLHNKKMHPJQPOM>fTqbVRSUROTA6Zj_zwxyyxwvvuutsrqqpoonmllkjjiihhgggfeedddccbaaa```abbcdadefgghijklnoprsuwz|~zýzļ}{ywusqomkjhgfddc gvxCIIHIFGH ECCGFeAEFFF' H#( 6Mehmqtx|~zvqnkfb~|ye%~~~~,4LDFFEDFEDDDCDCCB AAA@@??>>===<;:989889989::;<<==?|?ABCCEFGIJLMPRTWY\_cfimqvzżǾAǾ}yuplifda^[YVTRPNMKJHGEDCBCi敒𛕗7FHHGHIC@FHIMH@@GHIQMRSNSLQKNNKNTSTTSTTSPRH=byxxyspzxyyx)wvvvuuutssrrqpponmmlkkjjjiihhggfffeeddccdcbcdddfbhijklnoqrtuwz|~zmooppom~xĽ~}zxvtrqnmkjhgfediԁhIGGGJdzIGHHGFEEGCuCDEFGI&;dO|adglptx|LLMXK}xtplhd`\|xÿk$,$Ȁ}}~~~,5NGIIGFHHGFEDDDCCCBBA@@??>>>=<;<<<==>?@AoDEFFGHJLNPRTVY[^adgkosv{ȿBļ~yzwrmfec_\ZXUSQNNKJIHGEDEgϷ7GHIIIJJJIILCMt}GSR[cjvzFFMPOJHQSSTTUTQSUbvwwxspyxwvwvutsrqpponmmlllkkjjiihhggffedcdegfjhijjllnoqstvwz|~uzkoruwwxxvtqmiº{t»|{ywusrpnljihgfeiʅqFFDFHCFHHIIHGFEFHHEFGGH/#DDED#%$&(()*b6_O퓎w{X[_bfkoswz~GIJLMXLKIGE~ztrnjfa]ZV}zws¾p$~}~}~Ȁ}}~,>道QIKKLKKKJIJJIIIHIHGF DCCBBBAAA@?>=>>=>?>>?@ABBvƒIIJLNPRTUXZ^`dgjmquy}􀆌Ļ¼Cm~jngfd`^\YWY[QLJJHIꅑ3IIJKKKIJIHJhk|xwuooxsuxyFOUCMHQSSSTUTRVz1mtuuwwtvuvvwvu ttsttrqpooon mlllkjjiihhgfefffgdmklmnoqsuvxy{~sx~glpuy|~|wsni|vqkż|,ڀ|yyxvtrqooojgfgfiZu?EFEHI HHFEHIHGGHJI!AEB@@BA?CDEJIJ&(**);Z vy}TVX[_cgkpsvy~ADFHJLMNNMLJHECA~zvrmiea]YVQNL~}zwuspm)懡0~}~~ǀ~~,@䬨˷ZORNIMPPPQOMMMKKKLKJIHJIGHFDDDCBA@A@AABBCDEFvvJLMNPRTVXZ]acfjmptx|󀆍ŻƾDľ͹qzxmhedµѸRGGHJIIK7potzyBEABB@~EHqaORRUVUQW^Ig~||uls{{|}|xwwvuvvu +ssvutttrsqn mmlllkjkjiiihgfgiegllmnoqrtvwy{}pu{dhnsx~~ysmhb~xrmgƽ}x=~ywutloBDEGIHHIIHHHIHEEHIHGGGFGI ;:>B@$$A!!$G!A&(B, 1Xĺ큉prtx{~OPRUXZ^afjnru<>ACEHJLNMMKIFDA?<:pmhd`\WTPMJGD}zyxvutrpn4jhfĿʅW} ~~}~~~}~}~~}~ǀ~}~|~~~,S񀄑űܒRTRQTTQORSPQORQKONuIGGFFEDCDCDEEFGH{v˞OPQRUVX[]`behknruy}ƻü ٿ„4簄~JHOVVVUWPIIIJH5x@EEFA{AAKJGEMJ?VHORTTUVQRRW\ErѤrŹt||}|yvzzwxvzwqwvnlkkkjijiihgfghɥ˿nklmnpqstvwy{}{imqw}dinu{~vpic^~xrlgbzurʤ4乩gf?DFIHHHIIIJIHGEILIJLMRZWP/1101 @E"$#"!A!!)(##(& ) +6N鷩ц·Ƶهijlnruwz}FGIJMPSUY]`dgln8:=?BDGKMNNKHDA>;964ea\XTPMIGEA?=wvrpoonlljhfda^]]Ʉ#׽  "31}~}~ ~~~~~~{ |{zz}~,頞ɰޒ翼rȏ妄|hwtjygilʀjmpsw{~½𺏩Ծyѱm,ݓɚ뗄\ƿUHJKG?4HNPTNOJKKJ]XLIJKBXHNPTVXWYVPW^ElMI o¿ݜⷬɌ™ވӇЅπȁy{}vzhlqw|`diou|UVyqjc]{uojd`K~|tjiˀ@{ dèNAIGIIIJKKItGJeoKsTG[* %'')''%'%%50&&'($) -%Bz\湶̼ӘܦxKV| r`abefilnqsvy|@BCDFIKNQTX[_c35679<:9nmjhgfecba^\[\\VQQVyaˬ (/ (%,($^~~~~}~}}|}}~ ~~~}|}|~~}}{|{||zy}~ ~~~~~~~~,PѢˑļo{炓ѼɿXɁ땃ǚþԯ˷ÿש`^^\\MDGGCEhNROSMIIFJN^UJKPSFVHRUWLFMIGJ]bCATj [NQbFEیlee1]go]K͈nȵ̴͹͛quy}_cglosw|Z^chms{PY^^[Qwnf_XS|vpjea\~}lqf{\{iWZa׎w,ķLDFvFIHIHFEBA@?GdU]}HHHFG&')&('&&$%'2-$%()#( / +"LIEt^adHPVԞVWYZ\^`adfilo89:;=>@BCFHKMQU,./12468=!%&%%!<630.+)'KHEB@><;8754fda_]\[ZXVUSQnR}OIr`+jiQVZޑx$( Q=$'#B~$~~~}}}~}{{{}}{{}~||}||zw}}||zz{|~~~~}}}{}|||{{}}{{{||~~}~,򈅞ʩ׊ŋܗٓʺ}ןx}㒑ٮ׀󁈑ӽȾŽь²ҝϗ,ÀǽIEGAwA|BAr=5MMLOB@BCNOXVQXXSNZH\b@hKM`s]pY[yqSiiBsPxR@Pmuþʡ˹j}ؽjmquz\`cgjmqty~SW[afmuP_gRzmc\VQ~xsmhc^ZV{xw_|pArKQgaq,.؄HCGIGH@gfdbdb]U^\otA{FE@(&% <"@"#7&)&'  $'.+)..+'*#"'/!"!!((#c+!+G մlyǡWrۀxyz|}~IJLNORSUWY\^`a12345678:<>@BEH%&()*,-/2!/6#0,*'%#"B?=;975320/.-YXVSRQONNLJJJ>gWaPdY\GM{icu,.ʕ110/22/++)::=#!"~~~~1~~}{|||}~~}~}{}}{|}~~{{{|}}~||}~~|||{~~}z{|~~~~~~~~~}}}{}|||{|}}|{|||~~~,䳣Դמ͓ԄуᩛÞ{ΈԮիڀ퍸ڏɲɿûӬڗ䦝Ӑ†JHID~?>B?;@3MWRXVPNMNIW^_`W[VaNAm_zwkw`f.WbZ@^nBGWW:s@=I`kQDjyRmx|tPd`]՘PVWLgI:3_ίҀz|~`cfjnsw|TWY\_bfimquy~|KOSW]dn}JTdhHwg\TNJzuoje`]YTQM}yricb`Q?Uki~ֹnfg,}/UAHIIJCjjrjmkhZVOv{C|DED*)(#C! &,(*)&$"#!,001,.+-#& (",%G`ghc3HBBٯ.7 IƬǀllmmnopqrtvyzzz|}??@ACDFGHKLOPQS**++,--.0123458: !!#%/Q" 54210.-+**)('&LKIHFFGFEDB>AB@_Y?_;LRcgAhB_ESFbHB\BMFn9W9XOmMMH{BOLGL=Ae[emLxwrmbMPjmr{ۅigdWSZYTW_~€oqtwz}Y\_cgknsw{KNPRTWYa_{Wbvx}CFKQZh=arEgVKD?xrmjfc^[WUQMJG{xttdk]rCQvUuevrw,󠦴jXCIIIJColmmjf_YYY}=CyCDD()(#B>7<;0/8/$(-1 &! F+*1$F#(cN":F*LD@;X61#!&.cuq}p*-,-+/@AABCDE""##$$$'.6#r%++,,  )('''&%%$$#"!!A@?><;<4RZQC>R.;+@(\j\cŴ,阠Sv452342/+)''=9 "$~~}|}}|}~~~{|~}~~}~~~~~~~~~}~~~~~|||~~}}}||}}|||}}||}|}~~{~~~,犇ڻݚԤħ저ԑ஛턟īᱧ۲a䏓󀆍njۂȸr79gOƧȯʀ{}ts,ݼ䓖ȁGGF@|xx=rf;4@)#F$.>V6*-/(95PbmkhG{~ZEZ~BMi\M>`Gfz@M>DoXFJGCcW=FE?VHQH[PCWP[TKNKpvs_[YxphEH>V~eilnpsx{~QRUXY\`cfhloqtvy|DEKDtuCXWZ^`bgl:>K@+EA7f_ZTPOKFEGDCsr|vrnjgda]cmqxtyW^^cyƷrfpoz~},趨۵aVDHGHI@q;;hedefbW>=BwCFE%'% ?;97- 0 %,4J?UH5LJ9\#,6_%$)BT&F6@\.2'(T /-$//3/-.\d]-AMJ>.*"@ف)sNOQQRRTVUVVWXZ[\.//0011223344556 7b 1    E347664332204m11/.-/.,%7"$~~~~~~~~}~}~}~}}}~}}~~~~~~~~~~}~~~~~~~~}{}~~}}~~|~~}}}~}}~}|~|~~}{}~~~,󊚈ۻ˨⻚ރ֔޿ɑ֕왃²ټ˷~݋关ןöϬҀ~TԈÔ´éc⠔›ɞŨ,ػ}{DHF@{tx811FUxbLFB8@WxShPLe^x\go~^WZ}Ssir[LdJUT_mdaZvbқ؀zv{ӄ]bjod]ebh|}KNPSUWZ\^`bcegilms{\jB@B@@EHKMQ^KoGVNJFCBtRkmqtoweoi\\XVTQOKPaƲ_ă\Rchj[EOsvw,yk|˽˅}|gfMEJHIJC<=:gckmkg`?vCNW|RčLhblb^nWhCxUaRZKPsYM|{b~uetprԀ´{М}ٻkʿ„ۗzgoWWQNU^f^bdhjk{jbZfWsu@^H=]^dgB`L\WJU^Ncifle`QI|zbNjPclbiO@I|jޅ,j\`xpꐷ˹Ω^fqJJHIJCsnqdZ`_[B3Rp@vAA?#&$ ::qw 01#  +(=6Iy8KK.9VO5D2R3[)=J ?+ 1I#)*2F'opV'2.4,.:+6\L#9!@`2/a4$A?=SfgTe\fj_zـȨ蝪߃о_qQJVWXY12.,/260244329FI/1204D@!!!b8 #"%E%.214<5(%HJHHJHFI]{yOËO+88'Mx'$-?{j3t,ȁ6[RޔÖ6P>'3.10*(*'/66! ~~~~~~}~~~~~~}~~}}~}}~~~~~~~~}}~~~~~~~|~~}~}}}~~}~}|}}}~} +~~~}|}|}~~}~||}~}}}~{~~|}|~|}|{{{| +}~}|||}|{|}||~~~,ŝޚٵܴ;̻ۿ؊⃥ӊɋЌ؟ܒʼnԮs̨ȴکza9oLH2dAJtIJRMAxxA DbKh󍮗톁wQb}֜׼⃤؜Ԏг,ꑥ߳EID>=<=A96;7D2.(-VI4R>8OJ-*)4?KBDAPTLWVSUMQB8PR[Wc7i`fSZaXfk:aUT}NplquenGqjSGIEI6A:99chM??Gb[XnZFMZDKxPSKlLgjS`gp__vaezߕ͡voq{jtp~Vxlmcn_Hwqrd01CA{zqwusmg]}csvldli]nT,Pgbht_JMYHlwjctKHHIID:oKIgba0<9cB@ED? # + +%" "%&'%" '"##-/-//=,&+#/I841/E+;1;=38#7Z[A~c3 + $%%="%#+%NUATGg:AMJTzwӮvŠ{һʅ릋5(]Uu@*l[_jTmj~h{dbUjyvi}vNxIuM:$d\?GgD>:LG??L6Ff,'8>fV>FRS "DH<;'.$(B()'!2 ~}~~}~~}~~~~~}||~~ +~~~}}~}~}~}~}|}|}|}}}|}|}}~}~~~~~}~~||}|{|{{{|~}{~~|}}~~~|~}||}}|}~}|}|~}}|~~~,¥˅פŻƩډ˔Žɀ䒚̛˷읖ʋ˭ÍxɪԋáŸĖߡȍ彎sƦۜ܎֜,Ӂ聀ZMXUGNUIlv@8E<5,1`Gx&22A? !?("i9QHqfiQ[Ia{ǟ}Šyѣ[z~wȭqwRNDA8Z/lG.GRyW[ґ|_ǏŇm>.%M*%.e%#1UC-93/,-30,#%('>:841-'1-&#&(*'%.<5,UR(+24!"-9~~~ }~~}}~~~}~~~~~~|}|~~}~~~}}~~}}~}~}~}|}~}}}~}~}}~~}|}|}}|||~}}}~~}{~}{~}|{{||~~~~~~~~~~,ÆŖ׉ȗݕ榄ڋ߾듥鰂⫠մɋ㯕Տހŀǐlلҵ단ʷ̣Ϥ㟞ڥٵڏ|µ渠~ڴɚꥸҿَչ,˧Ÿ쀿ف켢ીue}I[M\^S:Z++*FGN=[[d]+j}OGk[[Oi[aSXaFFQUMA<>>6UV-ZTP_pankMESB@A<}ZKb]^TaxQfVdDdizfQNoR]W{̱͆lwtyʡx~gwwv|\Yh[{ޫ}m~ĞtYծe[`[kcCD>Ixrxo֦BV8k0$44"IFH5,())','( $&$" #) J)%-/*;kLc>,Va#265'7/176]U~~~}~|}~}~~~~~~~~}~~}~~}}~}|}|}|}}|||}|}}|}}|}~~}~}|}}|}~|}}~~~|~}{~~}}~~}|}~~~~,¯ť֡ꖟ咑ݷꏩЧΚۼҵ״Ɉᵰ䯨ɯFLJ5椩۶捡yׅڠu竍㚤Ȫ٫n„“•޺,݀냞]Ϛy]asncfsbV]2#&+,EFHO'DFEE%-[%-�:@*#c+;'31 #&F((3/!R.Q(#4834<@AB@ID{sy|ݒyҳӏvîق{eU`oYiMrtnecu^_s`eXZzc:d7+P,$=F3:grAF6jE48",!"710(E#,B6#&,8'&1Zw'.(-&A}]+6?2%S Sw)9~}~~}||}}|||}}~}~{||}}}|||}~}|||}~}|}|~}}}~~ ~~}~}|{|{|}|}|}~}~}}||}}|}||}}}||}~ }}}|}}|}}}|}~}}~~}}~~}}|~~}{~}~~}}~~~|}~~~}}}|}}||}}|{|}|||~~}|}~,ޖѶ򃁀阩舖ƢՅͰGɵѐԤŏךƃe]㠙tuωݾwwŕˁU擊֟{wppͅę۵\fdgyxmpiړꛌ,ꄾύةǔ׫̂]jzvnT_[qpZ^VVYb`cqᶤlM儎fXtjGZ=Aq`iUdVTZK{٘c`Op`tzmigwU~Nj̟Qy|SenKQgl`S\Āx{u~{xу〯|ƎՀdRg^D~uwWg}i|n}yywͦY]~kqqw}y]Mk[|eofGbjDA@,y>nCaltd\yQjJx[uu^ih~j~~Ra]ISkabownR5=;TSFJGIIMJHdԖ^gf/ᄆ~TCky{hJ-5"".A%:ώ.TW5s<>,+hGjuC\>7Gր΂uZooog^`i{ˇ熶ހÅ܈gmcHxq6ToryjV^įԛmזLVhԔu@:vyK^:\iM_Thq%gOc_qyzair}~ⅪƸzɜɴyztihmWpֵriD@BA,{{iCbwzVQMNTim[_z\bzYn_kfXme}tja?7^\mEJCBxt`BuC4~uqTCS9ptyaHdW}g~{Qy}\$/*LL$)imD+C,2@LXd]6kPkg6J\p8Tsft0~B[kV~~υКfqq}ʃŃNji+YPrv~vMVuVzxᠽ]n|vӳnjAQtu_:_]¤jC97! ,==/0<-*;3""!(+A*;1:vpwbkihpLXgFhP\Y~}~} +|}}}||}}}|}|}}|}~}{|||{{|}|{|{{|}}}|}||}}{|}~}||}~}}~}}||}~~} ||}|}}}~}|}}~}|}|}|}|}}}~~}}~}|||}|}}|}}}~}~~~~}}~}}||}}}|}}}|}|}}|{{}~}|}}|~~~ ~~~}~}|}}||}|||}~~}~}~}}~~~,ԺӒϿ۪—ǎ䖀Ӝ暯٠׭ǦqCáԇ؆Ûm|qxʽ覗О욍e㑚܀r~巄p앑Ѷ՜즹,鵂󓂉`ۆlwpsrsonUZYg҂x{]p|s}}VTPRRacmsw|ń^a`gąevNPnrxSK5iRKkli|eʩ~rZyyw~ϲ㣕zꘆԮn}Ďcp؛x}nk~[zŞa`nnO]eZΌrÍPHAABA,??l|bH[bbfXWP@oa|̽ö`xrxkql_aacbd`kl_:EHoqu|OՅێʆ|}>u]wd{v~Z0=*&$$Bac`zwP35>KyBZv:GY[b>%^7)bQMVu۷{je]Ԅbtqi`˳۴訖kα}䰝TΡѬc⊇kcw{Ij֣ӣGHXlrrk}AJHJfZq2{{]Q&# ,220'$'),*'9ñO\WZbg`~}{|}|}|}~{|~}|}|}|{|}|{|}||{}|}~}~ }~~}||}|}}}|}~} +|||}}}||}|}|}|}}}|||}~}||}}|}|}|}}~}~}~}}||{}|{|}}|}}|}~|}|~}||}}|~~}|}}~~} ~}~~|~}}~~~,ܪϽژ隬ʂۙḙɱǴӹֿ趄ړ̀׎m}z}ˮcݙkhm栔峙̄᝝ӞⅢҒоyɖ砻ҕ̓,ձưJX'Q>-ABCBSgNJEFCB@?XE۩laRwx\kuTVWVUTTT~tyg]Jxzaa}xfa\[|i{ЙlRRPLolaPmiXuɋus€^`y{zⰨʓqwziǶs[}qYpwRM|ۢ~jc̅RpklkvUECEC,@@heds|sfQMaxdu~ywzmw~t^M5}|IlNm\@FBD}?AABx~}pm֒wZG+O?gocTpflF=ԓ?tgrf_nk@`控b<#(.sISN8IK5iyn|̀ZlSr}~ҕκ䅀T\wdI_jgdT=ܮRqhh5-[]aǾyWP{p㖦1DHt`\h~}|9CD ,0)*075-"h޺̷nth~}|}}}|}|}|}}{~}{|}~}||{|{{{|||{{|||{|}}{z{}|{{|}~}|}|}|}||{{|}}|}|}|}|}}|~}~|z}|}|}~}|}~}~~}|}||}}|||{|}|{|}|~~~}||}|{~~~~}~~~}~,ϕȵ݄ꈁʺ삌ߛÍ]օԘȥĐMYʱёƼ՗ɿׁǻƇ޵žy΂֪ӵlЀï㖤؁рһsԬØK܉Xǽȳʅڋ,ϼ妜d],,(%91=BFEW]>9GD9602IqqbwsQLQTU~L[MtrdŜjyuwxdJGs_QehdVu\ކ˷yomdυudpzx}…gt`su^G]ޱ͵]iCC4HϹ[[Z[ZXTliwyo؍{{PTJDHE,CDktmfU[}ʔekhb]hZáu~|ve]X]stu|un|=7pAA@~}|}}~SXiXnJ1B8LΖ{e~}mufoxxyln[}mBFQSA7771+//26:7*<荐niv~p~|~|z~xuawzTRnh\uHiPat|vΏxۋi||f`uȺbuxbdeUCquMgilƥx׀ϖicyumsoell÷`dۋzqt̞{澹izZ_`ń]U;7#DokqǾªusɋűo~{w~TMEEE,B@dmjdgea][[]_l_|xh^Rn|zxtruLmvBA}~~}|xvZM9Dp,:*@c}pvfȚ́k`nN:urgNJ>}zkwcdj{tSdҌd4R[K*VRP-c7EV[`Ҫbb̏o|YNKtndij^be݅Ѐn뭶vyvUxoIPY̋"Rj!Sgv^^bgFYycppsYX+$" ,Lμy}s~~}{|}|}}|{|}|{}~~~{| +}|zz|}|||{|}|}|}|}| ~}}|||{{{|}~}|}}|}}~}|}~}|||}}|}|}|}}}{~~~~}|}|}}~~}|}||}||}||}|{}|{}}~~}}}~~~~}~~~,ͻ먵⠷َѸɲüԕ͕p΅کͬѷw^XOPJqqp秫~ͻづ݊Ăuā˵ҒԎˎҗ ܖU'")2>BBDD@5561*,.-2+56=҆modz|wyzxΥryt~RTs~umE@q¿Uuӣ̓Юv|Kqv]OvTE9=}x졁ɂs~䚪xoORUSMTmtmglcw}ˍˆ݆¶tڜb]oRhiS[u]dM5^tĒșze¾؆j}wEF,K^ceb^ZXXYZ\]`bmb{vhRa{|xvwxw|pwopq@Az{{z}|xze^qʟ^\YKT[ߋĂ0lpXdчyzmsϜqOJiX"HvqQ=0D8-YtN^\tta{ۘ|sɩA?CFFFISƞ}ᏈIoӐDIWb=JG:05@4! 'i]⊔xOWScɆnv\hnW:4$3܃ׄ {u}~}}{| {|}~~~}||}}|{{||{zz{|zz{}|||}|||{{|{|}~}~}~~~}|}~}|}~~}}}|{{{|~}||}~}}}|}}|}|}|}|{||}}}~ }}}~~}{|{|}~~}z}{{||}}||}|{}}|}}}~~~~~~}~~},㭨źͩ숍ηŃƺ^˖ȷqןp߃쒍xӀku竿Ҹؖ􅟫˽ʾ눿ӼƑò鳂ׁ̛ɴɵlu͙{s0!5=<<;=7--0*()(*)&01Hƻijj}oufRUSO~z||¡ydew[XW굿nm|ƚ卓I[^YЏqIUXyZLiy{s{yˉn\leb`}u칦‹Ѯ`y6ϑk̚mldv솏⊰h}xɄ{؅in\k~u`,ba`_[XWVVWXY[]_adfge{rـNMf{]nVfO=C@>w|{xwv~{u}zbGWL{NEC?ctӼlJ\b_jVVgvry~VW"2Ui<3Ożk3 !DF|.ezWxhl<{gLhaTɺdzoytq䪠vn~ѐåCOӓatAËZhG<7gcԀzysw}qxSVYynȀpm?^0Czbh,ݾ}pӆ}|}|}}|}}|{|{{|zz{|}~~}}| {}}}|}}~~}|}}~}}|{|}||{z{|}~}|}~}|}}|z}|}|||}|}}{{|}}|||{|{{|}|}|}|{|}}~}|}}~~|}}}~~~}{{{| ~~}|}||}|}}|{}||}~~}~~},̱ɊijҁϪћеɬxáڹ硟ͮ_l争̀䓤ǀւςʷɗsԟ죕ЇڬΑԎbǦwPAA?11577575(&(('%%#%%+,VķyW]yxTVTRuɼvkskζҶxۯeȩ靈Ȓcc܃zWr}V|Sd^Yеߙɀ➇^broؗyأ‰ᤢʼ_ggwi_=q7Wot>JSΫ{QnfXQ]BA{{vqlpvs}U`a][YXVWXZ\^`cegggi {zր~T+1Nyx{{xy|ytxwABB={zvvwsſuĶwYv}Zc^xԁހwb[`4ּseefo>FVgyS/x䝖.C.)2L|yH-~ҕɀT|R{ano}daݭȸѼŝfȯOrLOeZ5%H V\81;%*q}}ŐpSwnd^WRU[]kޤ򂔘}Є}|{}}|}|}|{|{|{|{{||{|}|}|} |}}~~}{|} ||{|}}|||{z|}|}~} ||}|||zz{|{|}|{|}}{{{|}|{{||}|}|||}~~}~}}}~~~}{|}|{{{}~}~~}~}},ޑD턀ŷ}ӨŊtm㤋ӷϘðYύo񪏤рйĹja|бꗦ䊢ˀǜ䊎ބɾ鈅փlgedfga^-'$"-00122/#"%$#$$!#+뀿buSXspossvtxxzSձwrʫ~㊺}vvqryယzߑrҏs}o̭i|ILeM_ovǠ†vxl۫ȼl;Zӟ̱yƂnuhsow~{VoB9T2FA?>B?@=txxfc]S{evqsײ}cdegeec`][XVVU VXZ\^`bdefeπKj$sfghotxyw{>y{tqpബuoè׃썿{脈e\`_`d`TluRe~XIUqͷuY 1.7R`8`~Fle^_ʮᾼf)RʞjZn{uab|ZJKDJQMCW$%;#,&%"b1cUZ[MHF;yhUjbd~̄}~~|{{||{||}|}|}||{|}}|||}}}|}|{||{||{|{||{{|}}}|}|||}|}}~~ ~~|{{{|}}|{{|}~|||}|zy{|{||{z{||} |{{{||}}|{{||}~}~{|}~~~}}~}}}||}|||}|}~}}~~},Χ{wyԥӣ˷⿺vwΓ֝c^䨘ɣ㵉s͵hح֨񖲦̗g}۳ݮzylhNnڑmĽᐔ堂͏Ԝԧαيfjd^XTVSPNJGDB?<9840,)'$!--)+.,&%##"!  .ƀfa}tuwwΊ}wͺ򶘲޿̹ywhpsmjplzʣ`{h{ձV`Fˍσb{ภxou^z{hÝǾ|egCg{|qƷt|~ɄfkkyfjsxghlcgKKLTXWX邱ƞ|zvuttssstsqpnmkifca_][YXWVUT UUWXZ\]`bdefef]Ԯ4a񖁀rwwvwruy}jtv϶›ȣ׆JKMHGyW~ХNqq͵^aIq}mh9!#qCZ[1spUIhS,]sj̀Ⱦq`_bA@TXfgoyIJQSROAHKRQ86>>BDKnYgr{iyrѷ ו֫}}}|{|||{{|{|{|}|}|}}|||}|}|{{{|{}&|{{|{||}~~|}}~~}{y|}}}||}}}|||}|}{|}|zz{|}{|}|{|}|}~}}~~~}~}~},҉ԁ̡͈︦ȝt֟hoſ蓛ՋɬؾӦޠ히뛆vXgwÀPzp[|ՖՉRHZj͹даԂԜɽ׏ɿ矹׀ݛKKHDCA@><:742/-*)'%#!  &')4րdhRbwv̾섟y}Ƥsą{ߖ̚zqrcfe`|֯}eöwuvG:vnx Dlo~bB0]pyqfcpۻɾXxeajnszrcXê톏⌗ػ|zwtromkigedba_^]\[YXWVUUTTSSTSTT +UVWXZ\^`acefd\[\[[\[[\ؾP^A"}~u}umkuzTsź£|юߦ艼ij~AA:UGj̱c}qδƼ~ح{܋αq^mqg]U|k`cݯů򄰆w{trpnljihgedba_^]\[ZYYXWWVVUUTTTUUVWXYY[\]^`abcdcU`[[\^_^ +]\_Owrouu:ߐܞk¬dof`kzʋxwK``W0wwz{|xEAU˭gHM;#".$-KZŸŒwߎƢatDLknMID?}vwvpSKD?NS]zkawv5ˠ}|~z|{|{{{|}| {|||}}}||}}|{zz|{z{|}}|{{|||{|||{|}|||}|}}{|}}}~}|}}}||}{}}zzyz|}~}}}|}~~~||}|}~}|{|{}~~|},Ż䒫vꄃŷp}ɞdîueQĨ`t;CJpżƀyœɬcvWKwpƹ쇫ߠջѵ}&.)(&%#"    + (ՀmWipqx~rnhey{}xǾ{ܧtյ~zkîy[dexýȊxwrŜcACVVVXWS{ptof^a~zkgbr߰QK>gT׵᧲xꆑk4:mr{nb|c}wñኝsvpnkhgedcbaa`_^]\[ZYYXXWXXYYZ[\]^_abccdddcbcbcWTb\\\___^_^]^ \agĻyRlHWqryoi`Z{|~|ڎݮȰꑖʽ퐵К{rqi^j{}puЉoE+-@>BEFL({ahy]A6EvНjΪQN:NNЬ|ٺ»ҳW*,RQMcmf`YPCuSCUTWUj|zeO~ ĸ}|{|}|}||}}||}|zz{|||{{z{{{z{|}|||}}}|{|}|}~|}}}~~}{ +z{|{|z{}~~}~|}|}~}|{{|~~|},ϻރs|䶰by\οyTJA667-5~ƾҊuλΌԻtvQ^f_ceikknnyphjv³tQj?eڏŤյޘ邭̡)&$"!  +   +H܀nvfr{}rnnu|~v}ۮni~Лvi\U[c\]܋̼՚SXvo{REMNQTSZlkWXasf5oDdho{؆erzvy}xyп˞ݒ嬾mIX:Ers_~~Ƣx{uplhfdbbba`__^]]]\\[ZZYZZZ[\\]^_`abcccdcbceda_a`_]]^^]q|ʀxNtumuy}nhjry~爋Ʌɯgdj˥ݰB9|~r]hqztj|c8.69;>A=R^E=@I@43gRs聏Ӹ\F?J0;ZsR`mm[vBTWWZsw\;ھ }ͅ}|}{|}|}|}|{|{|}|}|{|}|}~}}|}~}|}~}|{{~},·è~{vǶqrb>Rq]uuԌ]?;(`eæ՛ׇى󃈏ʫ̠DŽpԕ}Ʈ}eQA1"%=MǺxսˣƦ񏞟/"   +  $̀\嵲o~~|rr~wzzvwzqRik{뀖l[^I]trŻؗ暋Hhxs~㮻qmЮş]e\\gpFHea⪡gUV_q{}tfpòxŐ^laeO<{yiw|}xqWĨuijfdba```___^^^]\[\]]^^__`aabccdcddcbaba`_^ ]]\[^w~ÿgIixw~pkqwqԼn~u₈˿ٮtjf`c߷䔷0Mzvggoxwjr~dt\]kj˙@=4/06&SGuڔK7:*hDG\OzEJIJ_zbfʧųvk37FUWOTXVows~wwxzn]BSXͼ}|}|}|{|{{{|{|}|{|||}|u|}|{|{||{|{|}~||}||{{z{{{|{| {{|}{xzz{}|}|}~}~}|{}|},ٶyltہqgkxz{rxRv猇ͣå˪U򊐒mȁtRȽ~p}}}~򙭜 + + + +   |vhcptvyúկzɺ}~|rzih}`bošõ[Swd㢠[\\__[[kuAo~¾x؀~}}|q|~plsБi\ʏYb`__`^^^_`_``aabccddefedcbaaabaaabaa`_]]`^\[[[ZZZ\x|m[WOjqv{蝩۳r}ɷ]TMgbhrrsnÿkYPf_<2T[WUYWVWYYX]sg>ʿ񍇆aPYZNLSt}p{|trro]G}|}|}|{|{|{{{z{|}}|||}~}}}|{||{||{{{|{{|}|}|{{{|{| {|}{yyyz|}|}|}|}~}}~}~}}|{||{~~|},􄄉zˎzhqzdԅndNk;D|ffkv{xtw{}nUlg㕒Ӟ¡ݶ䇎UޫdjlzXKõrjlv|㍯|൓W + +   +#Ǿuxo¹uw}yww而wʉtjx}v䏸zwf_yyy}oVk{zuir͜Ԙ@!9Q:Nyrb]``eimoopmkmoѱĺz~y{ƽtpr|{y}{rkmqqlgęT_^]Z]^]^^``aabbcdefg ffgfffeeedcbaba`^^``^]\\[[[Y_vGwaogqv{zyxꄖ߁⚈愥旷ʭ琹⃋⛛Z5ۇ}VUflƿutom|jd/3H.=jhfQPRX]chikjhksϩ|ïܰp]UTMISUk}mw{tvvmkiW\}7}|}|} ||}|||{|||}|}|||{{{zz{{{|||{|{z|} ~~|}}}|{|{{||{|{{|}}}||}||}}|}}{|{{||{|}|}|}~}~}|{{~~||},Ÿ􂉆{{x|}Ń{Ʊe]gO7-7D,<9{itywwvkarrѕ˳ܾՈTwӚ^JZdeeuφ~툤Ųd + + +   H~ǀzxʹxzw}}xyv~ɀukļoamVyyqj~oNjh}}zzȗ~­ƜpY:bIv[eknnnoqtutkqui^յݫìvnonzxnkfӭ{cfΙ\\\ZXY\[[\]__`abcdefghgffgfedcccbcccbababaa_`a``]\ [Z^Ǿurx~w󂇄٥̡铅䣪İӺgYLݎf*geȼnqmef{e~pTaDo\@fEQX[]_acgji`fofKƊѶüjVIFbugz}trpoiiR\h"dž}|||}}|}|}|}|{||}|}}|||{|{z|}~~~|{|}}}|||{{{||{|{{|}||}|~}|{|}z{{|}||}||}|||}}}~~}~~~}}~}|{||{{~}{},ŹŢ}xw~{uo}vd]}{[UxYeĒ^{nʓӇĢθն؀Uͯꆅ䦔yY]FZ`a\U_fֳ嚛񓡖sh  +  Āyyxx|ww{usv|qjzlj{td~vъ獭v{scln|}iɳ˨xcϤnbabikqtvxsruhRذ᠒psohpsxjfȽfÕэ|\f|]YZYWWZYYZ[\]^_`bbcefffgfedcbbcbabaaa`__]]]\[^ͬ½Ȼ|{~~wwx|ڀ׌⢖{a||^TFv}ЃnU^hdkkU~YgdxbTQRX[cfinjkqdA뽩⤺Ǎɺ_KCGmqiovtqlpgβNYCjշʓ}|}|}|}|{|}~~~}}|}}}||{|{||{{||}~}|{}}z{|}|} ~~~}}~}}}|{{{||{|~~{|},Ǽ~ߺyy~~y|ӿȸzе~mvx܈εPͫ6Ѓڝy_Jo|\@\v~ඌ儜ܛh   +  ~Ȁxturtw|x}ݷy}{}׽ǼȩΎ}t~zv|j~vĝԁ҈ytʼfkǫۋƾɣR˼ڬ|tcehaãۢ}vghŠv|_TdǪ\VXVUTVX YZ\]^`aacddeefe dddcdeecbccbaaabbaabaa```_^]][biCijtqroqu{y֩YY[TRU`\Lv茆ܞxKvcgѢv|}xx[uʦzq\_b\p̓ڲ˶YBI{YjlwzsqmlfżSKUH2ɝ}|}|{|}~~~}|}|}}|||{|{|}|{|{{|}|z{|}}|}}|}~}~~}| {{{|||z|~~|},ü}}}}uop}sοkŚvph󒪷🥧£eȵwր¹⑐ç釪̹OͯǯƲV|WzKSSae=Ɋȟ⊛ۮzd +   +  `׀Žzx||~~yttvpƬwxvwyx|s`ǃ᎟ÇR;`b龰ۦ쉣Ƹdǯ´{ps]od׋Ųvhnпgҷ~|URZTWUTSSVVVWWYZ\]^_`abcdddefefffefe +dddcbU_cb aaabbaabababaa```_] +xxЀȾ{y|󌒊џ񎄊UUSYXw;^}L:\_ƻʝr~t^zqʿ_\而͔ǔɭGJGejfttrrmkjeķPL ˏ 󓙚uܛ}|}|}|}|{|{{z{|~}|}| }}|||{|{{{||{||{{||}| }|zyzyz{{}}{}|}~~}}~}|{||{z|~~}|},Ź{tz}vpvqwzsqrξФm󌥵bϾʼnПāݾNǤؾιåϜ̳n=Ĕ݀za  +     +  "𖬼ƀz{u~z}xq{v||wst٨݆󏥳zzyy}|}㻪vݜvϰYab꺬dÞ˨ܺ~m{ߕƳdfûݨ|VJT·YSUTSSRTUUUVWXZ[\]^_`abccddefe ddcc_wW\dbbcbabbababcba`_^]cV{ӎUUSV]]ȍ뀱UfR^\Ϝ´̓x^x||xpXU_vͲʪAEeesrpqmjjheKGM ۔ IѤ}|}}|}|}}||}|z{z{|{|}}}|||{|{|{|}|}||}~~}|{|||{z}~~~|||},Źv{vwv{zϩzȩS]ס˹ҸžքˊƺڌӼ؀NŦéӷӳնǩt6Ǧаꎓ|Z + + +  + +  Mŀzyyz~yѮsϦgj߄Ÿzzzyuy̖ؾ嗚ϊoRSݲԂd~áʿέϨ̯Ѳ͵ĺuܾ|}|uѵLFቀWSUSSRQRSTTUUVXYZ[\^^_abbcdded ccZQ_bbcbaaababa`_^cJ!ƻ늦ѡ𶗼텂֌TTSTSY`ӍZX{LM”ɻvf||uvrŰԤ9U~auabqvsrmjkid_FCZ 7Ƨϖ}|}|}|z{z{|}}|||{|{|{|}||}}}~}|{||{z{}~~}{|},||{𿦭َڳR܃ꆠ̶نϫŶǼMɮǺǾijϻƸ˸x7Ïī剑|Q +  + + + + +  ˉz||躞طܭȸg򂂔m|hyvx{wwtƆ׷嘟ڮ}U\کc򒚓Ưʽ~ެ|zҹOD{xSQSRRQPPRRSSTTUWXYZ[\^^`abbcdededcdcdeecbbbccbcbaba`aUńĺ󆕕ǨLGRURSVSTR܅겍ZnMV|Y菥ytxzrxrͺڡosfaktwrpmljighcJA"ҍ}|}|{{{z|}{z{|||{{|{|}}|||{|{|{|}||}}}|{||{{z|~~|{|},|~r|}{ă|`ԃ쟡簺}ϫ໢ᵱK偕voD{툔rI  +  + + + + + + (ǀ|xxtݡzukygvwwxwwr|ڋ߮恆KTXڗe䁔拑zn}|yuuӷNGC髽{qPQPPPONPQQRRSTUWXYZ[\]^_`abbccdcccbccbcbaba`a_erTþɾ¿ג~ݔJEQRSRTTURz̿ꟷb\{|sCNUŀxbqvt|mxr|y{`̨Ngafrusqpmlkihea__FD>Gς:Ώ}|}|{z{{|}|{|||{{|}}|||{|||{{{||{|{|}|}}|{ |||{zy}~~~{|},vyٿ}u~žĮeY}̃蠠˩өlw؝y˥ńP|kE񎙏wz>  +  +  + + }~ޅԂ|tfs{pioxgvxxuuvxհݤt~zLR_G|~Ɔ}zwtβJCD㍅ւiONMOPPQQRRSUVWYZ[\]^_`abbcccdc ddcccbcbcbbaaba`__]o}𑊋ܤ׺ᇅIFPRUTRSUX覱߀Yn{puHP[oľ]oyy{|tnlŧa{qnnnoiighfca^C?=w$銛 }|{||}}}|{|{{||}}|{|||{{|}|{|||{||{|{|||{{y|~~~~|{|},†Äïmkwnmzу䜞¨Ťçr|u̡¤IbCy而֛r"  + + + .≢˂vrqzosyhzguwwwvvsĞɦӦ{x}uF~~}}yz{ytVKA?կ舃YONMLNOOPPPQRSUVWXYZ[\]_``abbcccdedcdcbbababa`^cއ쒯ƣڅπLGPSUTTTUSĘƅүĺ񉙐Z^zqn|j_qttuxuupntusvwwzz|x|š[ohddfd`ccb^KG=8p`뎩IJ}||{{|{z{| }}|||}}||{|||{{|}}}|{|{|{| {{zz}~~~~{{|},Ϣۆ~̝徟޿ٟkȹ䜝жn}qýOZCpڰڲqj{R  + + + +  b|~őڈ|ɛոݷɘo𐀇sivwxwtw|v۾u¹{fMýE~|~}yuzvwutqųJCC?ۦ~{zOMLLNOOOPPQRSUVWXYZ[\]^_`aabbccdedddeeedcdcbaba`__zh~vļє엞߯ѻޢ󂾋GPTTUURV]m~ɯ҄úSax{\J_nlnmrttvyx{|z}rnyzVja^`^][A>@8zR勪큁 +s}|{{||}}}|{zz{|}||{||{{|}}}|{|{|{|{|{| {{zz}~~~~}{|},|vØ{ڪq޷ݛɝεɶ̽prgxܴ͑H\ChɫwinZ. + + +  + 1ڃxs~ѥo~zߺv}ljvutssx}ȓ񠳧Ӷϻցx|uey|NRXg|~}}~omysòMA=@Äv}xaNMLMMLLKMNNOOOPQRTUVVWXZZ[\^__`aabccdededcddccbccba``_cQ~º͜Ԑ庂աЏxQQTSRQRTkvɑ矴ݺuw?ZyhysHLSGnpoosqttqpmp}wPc]D;9;pu+Đۂ>ሣ} ||}|||}||}|{z{{|{||{{|{|}}}|{||{|{{|||{|{|{|{{{zz|~~~~|{||},ׯywενluڥπݔ἟Ƴӷк¹emi}❙Ԙ񌓕J¿idǩqjkK)   + +   + + kۄ~Ûsuuδ{͘rtΘ|{Ǯppnty籘ʶղֺt˰vmydɍISWZCɽ󁄉ʾE󂈆xǏd; +     + + +  + + + +) 3=ׇzwì؃ㄦ{|ztvܴvΊz悀q{~z}ux~^}~}}־nutKKLMNOPPQRSTUUVWYYYZ[\]^___` aabbbcbbccbcbcb)abegclRy{}ƭ≣½·Ļ郘ɮޑÁ傤腎瀑d}~³ʊwen,AбҺψ}|}|}||}}}|}|}||}}|}|}|}|}|}|}~~~||{|},~}z~y{t{notx{vʁҟ~sψxwzx}D~񆊋xpvz}V/    + +.  0?Pys{||w|z~uzsw{|{wɀ͛遇u֍}z셂yy}~b|}xz遅yuz~~}dltJKLMMNNOPPQRSTTUVWWXYYZ[\\]]^^_```aabcb+dfhcavxŸ兜Ȃ׈ܥ񠤌`~y}􉌎z[fjq٦ +8qxʀΥ惞тÊ}|}|}|}||}|}|}|{||}|}|}|}|}|} |||}}|}||}|}~~~}|{{|{|},w|w{zyvyvwrv|ށؽ~䋑~̅w|GU4 + + + 5 + + +  =@tzr~{}{{~x}y~~}xں{wzx߀ֻ{揗Ԉ邈w{~|~n}|~~|~͵fnzOOONMMNOOPPQRRSTTUVVWXYYZ[[\\\]^^^__``aabcccdc3bbbdeghf_uЅw~艆ɇǩ]Ӱa^d㞷󇎏6ܔoeѶͷ€½ɲ}|}||}|}||}|}||}|}|}|}|}}|||}|}~~~}|{|},~}~~~틔|ْxzy|y|usyð~{}z{~OÙꃙzKM<)   + 7 7>}ُ͊{sp‹~|􄔞}{~換}ۓy{{{~uxyҿ~zyy}{r}|{}ڋtwcWb{mQSSRRQQQRRSTUVVWWXYYZ[[\\]]^^___```aabbcbbbaab6ceghhgbYvjph}xvҘDZÿ͌рũ與򎨫j󂃂vouZGKi=ЗQSvūˑī¾š}|}|}|}}|}|}|}|}|}|}|}|}|}}}|||}~~~}||{|{|||},}~}y|v…wyywx{yyz{|{ŷ򅋏|szyYႁѫԁMC6) : 19:rӯΒso~Ӗr}y{~~}톙yŅx{}{y}{z{{{{°|񄈏~w~퀁{xP}~}okùƼ_t|TVXYYXYYZZ[[\]^F__``abcddeefggfd`ZqPm`n~۝y܏ׂ˷}UmhûJ[|I归:Re뤧}|} +|}}|}}}|||}|}|}}|}|}|}|}~~~~}|||{|}|},zzww|{{}||yȆ}z{~{uyxxu{~tvzռy|~`~ͤB=?6-( + +  H + + '*2425utѹԈБ}|xw}zz}{{~|ʈ~z~~xzzxv}vvވ||ھ~{|}_}yz~nt}UXZ[\^^_``abcCba`]Zykޘd^Qdڍٙ¹ߐﴂ썃˾慑˜{xrqw_ԻިS\DPw,ü}|}|}|}|}||}}|}|}|}|}~~}}|||{|},y{yԉz|yyxwywtyzz||ƶ⁓}Źyvsxxz?=;:75m|yidjgcʾȾ~{&ۂ}zzv،{y˲zwyzxw~x|{|ɴ􉎣~䅙{{~~򽯑~ulls{fghifcŽ~۾y_Oxecgin{,䇓͹혙ۄټ³xbYWZkڀ򀂄ÛoO;QFM^oõ,}|}|}||}}|}|}}}|}|}|}|{|}~}|{|},~|zā~{yۍ~vv{v~~}}z婏y|sǿʻ‡¼,₏{̈́|zxw|y|~}}||zy|{{xrymdpsjhrzļ,熔ź~¸񊢙ݍ쀄ÿ·ƛŶywww~vukg^Y^XQ^b^cvэ˼*}|}|} +||}}||}||}|}|}|}|{||{|},z{}~}~ux₅~~|㻚x~v·ڸ돧ģ~sγѻ㏖q{{|}|,}|y||~}{w|܁~~z}~߮z}ʻ̲捠{tԻЮ唙vz}z +¼ㄉ嬛ǼŨİǻㆅ,ƿ½Ŷ}|}|}||}}}|}|||}|||}}}|}|{|{|||{|{|}|},~󃎖u}yy֋}z}|zܛ}~wz{倁y|w剗|Պӳقׁ}݋qxxz{Υ},|z|򄑛x|厏ڢ~y}}~{{|އ׿㇇vz~|ԫ,|z뺄ȿ 􄙛ƽ򒣗Ϧ勻޷,}|}|}|}|}|}|}|}||{{{|}|{|}}|}||{{|{{{|||}}}|},~􄄅~|{~~~|}tᚂ{x|}y}Ӣ~~|zu|{񁄅~~||ⵀþý͞ss|pxtt}rtyz~vvx|}}|{y,8~􃄆~{Σѧ}xz屠𖞝ķp´Νxzx{{yz}|}~{񂇎׶뱀þ̽Ԣ̀,®}|}|}|} |||}}}|||}|}|}|}|}|},~|{||{{yxuwxvy{z~wx~|zx~܍||x{|{wyxtsuuw}zz|}؅ǩxz|,~{}~z|~|~x|֛~吒||}{~ywzy|}挞¥|,᱅¿ǿǩლġא,}|}|}|}|}|||}|}|}|}|},{ysruvwtu||}|~|yȰv{xxxtwutw~zwvtvy|ytsvsڀt}ͼ悉Қlљ,~~}~~xx{|}zz}̻z~}}z{yy||zxy{yx}zy½}̼툒؜u٠,遄ǑՀ󁂆ž¾򤯭쪸¾,}|}|}|}|}|}|}|}|}|}|},~xzzzyxyvy}}~}{zutx{|֢ň|u~u}z|}zyuusƿՀy~}xx~َ։y|,}~|xvwz~~~~~}~z}zy~{Ҭܑ{}焐||yǻ}|{ߐߐ$~{}ȼ¿ž񁊔v򃓜욨ŷ}|}|}|}|}|}|}|},~~|tɽqvw}~vĭg~{~~}|~rs~|t½|ꊟyy{|~|~~}vy|~tw}vz,yyxɻrw{xö~y⅛ ~}}z{؁؁ĺ򌠫˾,Ǿ}|}|}|}|{|}|}|}|},}~}zuvvsqqprutvy}{ukt~xxxzzxy}}zzyyvuuwz{zyxzursnputsrwywuvwxz{{zz~}{y~wjjmv}}(~~~zxxwy}|~yt~}~}}~{xxuv{zyxz}{z{}~~sru,þ,}||}||}|}||}|}|}},~~~|||{}|{||{zyvsurrmt}~|}}wsstsuwxyy{}z~~zvrrsv|,}{{xuqoprsvwuu{}~~}}yzwwv}|xxxwy{}~~yyz}zyy{z~}~ }||}|}|||}|}|}},z|~|~~|{}~}|}|}||{wwwvwxy{~||~{uqprsrstvwxvqtuy~ +}}z}}||{}~|yy{|}}~~}zusuwyyvwyyz~~~~}|{yT||}|~~zy{|{{|~}wׄ3z{>}{}}~O>}|}}, d~~~~}{zxuuutroprsstuuuttuvwxyz|~~ > ,~{{{ywvwxyz{|@}~YE&}|}} \ No newline at end of file diff --git a/testsuite/common/runtest.sh b/testsuite/common/runtest.sh new file mode 100755 index 0000000000..26da13b814 --- /dev/null +++ b/testsuite/common/runtest.sh @@ -0,0 +1,104 @@ +#!/bin/sh + +# +# the command line we're executing should be in the +# environment variable, ARN_COMMANDLINE +# + +# +# clean up leftover crap in this directory: +# core files +# valgrind-output files +# + +# +# valgrind output/summary files +# +VALOUTFILE=valgrind.output +VALSUMFILE=valgrind.summary +# +# let's make sure they don't exist +# +rm $VALOUTFILE 2> /dev/null +rm $VALSUMFILE 2> /dev/null +# +# declare VALGRIND and flags +# (to make parsing easier, we're using --log-file-exactly +# which will put all the thread-output in the same +# file--this might make troubleshooting by hand a little more +# difficult) +# +VALGRIND=/net/soft_scratch/apps/arnold/tools/rhel40m64/bin/valgrind +VALGRIND_FLAGS="--tool=memcheck \ + --num-callers=15 \ + --leak-check=yes \ + --show-reachable=yes \ + --log-file-exactly=$VALOUTFILE \ + --suppressions=../common/vlgrnd.supp \ + --xml=no" + +# +# get timelimit (from file, +# if it exists) +# +timelimitfile=`pwd`/tlimit +if [ -e "$timelimitfile" ]; then + timelimit=`cat $timelimitfile` +fi + +# +# run the test and get the arnold status -- only +# run with timelimits if we're not valgrind'ing +# +if [ "$ARN_USE_VALGRIND" = "1" ]; then + echo Command line: > $VALSUMFILE + echo " " $VALGRIND $VALGRIND_FLAGS $ARN_COMMANDLINE >> $VALSUMFILE + $VALGRIND $VALGRIND_FLAGS $ARN_COMMANDLINE +else + # only run with timelimit if the limit file exists + # in that test directory, otherwise all the tests + # run slowly (presumably because we have to load in + # perl and then interpret the 'timelimit' script) + if [ -e "$timelimitfile" ]; then + ../timelimit $timelimit $ARN_COMMANDLINE + else + $ARN_COMMANDLINE + fi +fi +arn_status=$? +if [ "$arn_status" -eq "64" ]; then + arn_status=1 # timeout +else + if [ "$arn_status" -eq "65" ]; then + arn_status=2 # keyboard interrupt + else + if [ "$arn_status" -ge "1" ]; then + if [ "$arn_status" -le "15" ]; then + arn_status=4 # arnold error + fi + else + if [ "$arn_status" -eq "0" ]; then + arn_status=0 # success + fi + fi + fi +fi +# +# now get the valgrind status +# +if [ -e $VALOUTFILE ]; then +#export AWKSUMMARY=`awk -f ../common/vlgrnd.awk $VALOUTFILE` + awk -f ../common/vlgrnd.awk $VALOUTFILE >> $VALSUMFILE + vlg_status=$? +else + export AWKSUMMARY='' + vlg_status=0 +fi +# +# figure out what we're returning to the calling +# shell. We'll put the arnold status in the low 4-bits +# and the valgrind status in the high 4-bits +# +tmpval=`expr $vlg_status \* 16` +exit `expr $arn_status + $tmpval` + diff --git a/testsuite/common/test.ass.template b/testsuite/common/test.ass.template new file mode 100755 index 0000000000..420b6e8203 --- /dev/null +++ b/testsuite/common/test.ass.template @@ -0,0 +1,11 @@ +# This test.ass file has been automatically generated. You can modify it for your own needs. + +persp_camera +{ + name mycamera + position 0 1 1 + look_at 0 0 0 + up 0 1 0 + fov 45 + handedness left +} diff --git a/testsuite/common/test.html.template b/testsuite/common/test.html.template new file mode 100755 index 0000000000..9a08ed3a07 --- /dev/null +++ b/testsuite/common/test.html.template @@ -0,0 +1,91 @@ + + + + +Arnold testsuite - {name} + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
teststatusdescriptionnewrefdiff-8x
+
+ + {name}  + +
+
+
+ + {status}  + +
+
+  +
+
{readme}
+
+  +
+ + {new_image} + + + + {ref_image} + + + + {diff_image} + +
+ +link to files + +
+
diff --git a/testsuite/common/testsuite.html.template b/testsuite/common/testsuite.html.template new file mode 100755 index 0000000000..2ef58cdaaf --- /dev/null +++ b/testsuite/common/testsuite.html.template @@ -0,0 +1,677 @@ + + + + + + Arnold testsuite + + + + + + + + + + +
+ +
+
+ + + + + + +
+ + + + + + + + + + + +
Repository:{{repo_url}}
Revision:{{revision}}
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + % if use_valgrind: + + + + + + + + + + + + + + + + + %end + + + + +
Patterns/tags:{{str(patterns + tags)}}
Tests
+ + + {{ format(total, '<4d') }} ({{ format(skipped, '<4d') }} skipped{{ ': {0} ignored, {1} OS-specific'.format(skipped_ignored, skipped_os) if skipped > 0 else '' }}) +
+ + + + {{ format(passed, '<4d') }} {{ '({0:.3g}%)'.format(float(100 * passed) / (passed + failed + crashed)) if passed > 0 else '' }} +
+ + + + {{ format(failed, '<4d') }} {{ '({0:.3g}%)'.format(float(100 * failed) / (passed + failed + crashed)) if failed > 0 else '' }} +
+ + + + {{ format(crashed, '<4d') }} {{ '({0:.3g}%)'.format(float(100 * crashed) / (passed + failed + crashed)) if crashed > 0 else '' }} +
Valgrind
Unit tests:report
Mem errors:{{memerrors}} {{ '({0:.3g}%)'.format(float(100 * memerrors) / total) if memerrors > 0 else '' }}
Mem leaks:{{memleaks}} {{ '({0:.3g}%)'.format(float(100 * memleaks) / total) if memleaks > 0 else '' }}
Total time:{{ format(total_time, '.2f') }} s
+
+ + % if defined('time_plots_image'): +
+ + + + +
+ % end + +
+
+
+ + + + + + + + + + + % if use_valgrind: + + + % end + + + + + % for test in tests: + + + + + + % if test['new_img']: + + % else: + + %end + + % if test['ref_img']: + + % else: + + %end + + % if test['dif_img']: + + % else: + + %end + + % if use_valgrind: + + + % end + + + %end + +
NameDescriptionNewRefDiff (4x)MemErrorsMemLeaksTime
{{test['name']}} +
+
+
{{!test['descr_summary']}}
+
+
+
+
+ {{!test['descr_details'].lstrip().replace('\r\n\r\n', '

').replace('\n\r\n\r', '

').replace('\r\r', '

').replace('\n\n', '

') }} +
+
+
+
+
+
+
+ new image + N/A + ref image + N/A + dif image + N/A + {{test['mem_errors']}} + + {{test['mem_leaks']}} + {{format(test['time'], '.3f')}} s
+ + + diff --git a/testsuite/common/usd/all.usda b/testsuite/common/usd/all.usda new file mode 100755 index 0000000000..421b52ff9d --- /dev/null +++ b/testsuite/common/usd/all.usda @@ -0,0 +1,29 @@ +#usda 1.0 +( + defaultPrim = "world" +) + +def Xform "world"( + references = @./grid.usda@ +){ + float3 xformOp:scale= (.3, .3, .3) + uniform token[] xformOpOrder = ["xformOp:scale"] + over "row1"{ + over "col1"( add references = @./sphere.usda@ ){} + over "col2"( add references = @./cube.usda@ ){} + over "col3"( add references = @./sphere.usda@ ){} + over "col4"( add references = @./sphere.usda@ ){} + } + over "row2"{ + over "col1"( add references = @./sven.usda@ ){} + #over "col2"( add references = @./cube.usda@ ){} + #over "col3"( add references = @./mesh.usda@ ){} + #over "col4"( add references = @./sphere.usda@ ){} + } + over "row3"{ + over "col1"( add references = @./sphere.usda@ ){} + over "col2"( add references = @./cube.usda@ ){} + over "col3"( add references = @./sphere.usda@ ){} + over "col4"( add references = @./sphere.usda@ ){} + } +} diff --git a/testsuite/common/usd/bif.usda b/testsuite/common/usd/bif.usda new file mode 100755 index 0000000000..a001481f3a --- /dev/null +++ b/testsuite/common/usd/bif.usda @@ -0,0 +1,16 @@ +#usda 1.0 +( + defaultPrim = "bif" +) + +def Bif "bif" +{ + float3[] extent = [(-1,-1,-1), (1,1,1)] + string json = "/home/beauchc/compounds/vel1.json" + string bifchannel:velocityChannel = "velocities" + float bifchannel:velocityScale = .3 + float bifin:weight = 0 + bool bifin:condition = false + uint bifin:subdivisions = 1 +} + diff --git a/testsuite/common/usd/cell.usda b/testsuite/common/usd/cell.usda new file mode 100755 index 0000000000..143e1ed0e6 --- /dev/null +++ b/testsuite/common/usd/cell.usda @@ -0,0 +1,10 @@ +#usda 1.0 +( + defaultPrim = "cell" +) + +def Xform "cell"( + add references = @./sphere.usda@ +) +{ +} diff --git a/testsuite/common/usd/cube.usda b/testsuite/common/usd/cube.usda new file mode 100755 index 0000000000..fc9462b2d5 --- /dev/null +++ b/testsuite/common/usd/cube.usda @@ -0,0 +1,8 @@ +#usda 1.0 +( + defaultPrim = "cube" +) + +def Cube "cube" +{ +} diff --git a/testsuite/common/usd/grid.usda b/testsuite/common/usd/grid.usda new file mode 100755 index 0000000000..243aad1128 --- /dev/null +++ b/testsuite/common/usd/grid.usda @@ -0,0 +1,26 @@ +#usda 1.0 +( + defaultPrim = "grid" +) + +def Xform "grid"{ + def Xform "row1"( + references = @./row.usda@ + ){ + float3 xformOp:translate= (0,3.8,0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + def Xform "row2"( + references = @./row.usda@ + ){ + float3 xformOp:translate= (0,1.4,0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + def Xform "row3"( + references = @./row.usda@ + ){ + float3 xformOp:translate= (0,-1,0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } +} + diff --git a/testsuite/common/usd/layout.mtlx b/testsuite/common/usd/layout.mtlx new file mode 100755 index 0000000000..f5fef0294b --- /dev/null +++ b/testsuite/common/usd/layout.mtlx @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/testsuite/common/usd/layout.usda b/testsuite/common/usd/layout.usda new file mode 100755 index 0000000000..7a7d5ef3a7 --- /dev/null +++ b/testsuite/common/usd/layout.usda @@ -0,0 +1,33 @@ +#usda 1.0 +( + defaultPrim = "root" +) + +def Xform "root"{ + def MaterialX "materialx"{ + string file = "/home/beauchc/dev/usdToArnold/data/usd/layout.mtlx" + } + def Xform "sven_group"( + references = [ @./sven.usda@ ] + #instanceable = true + ){ + float3 xformOp:translate= (-.8,0,0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + def Xform "sven_orig"( + references = [ @./sven.usda@ ] + #instanceable = true + ){ + float3 xformOp:translate= (0,0,.4) + float3 xformOp:rotateXYZ= (0,20,0) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + #def Xform "vespa_group"( + # references = [ @./vespa.usda@ ] + #){ + # float3 xformOp:translate= (.7,-.205,0) + # float3 xformOp:scale= (.7,.7,.7) + # float3 xformOp:rotateXYZ= (0,0,0) + # uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:scale", "xformOp:rotateXYZ"] + #} +} diff --git a/testsuite/common/usd/mesh.usda b/testsuite/common/usd/mesh.usda new file mode 100755 index 0000000000..86d9f23f83 --- /dev/null +++ b/testsuite/common/usd/mesh.usda @@ -0,0 +1,15 @@ +#usda 1.0 +( + defaultPrim = "root" +) + +def Xform "root"{ + def Mesh "mesh"( + references = @./sven.usd@ + ){ + float3 xformOp:translate= (0,-1.2,0) + float3 xformOp:scale= (.013, .013, .013) + float3 xformOp:rotateXYZ= (0,180,0) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:scale", "xformOp:rotateXYZ"] + } +} diff --git a/testsuite/common/usd/noisy_plane.mtlx b/testsuite/common/usd/noisy_plane.mtlx new file mode 100755 index 0000000000..2589ea564a --- /dev/null +++ b/testsuite/common/usd/noisy_plane.mtlx @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + diff --git a/testsuite/common/usd/noisy_plane.usda b/testsuite/common/usd/noisy_plane.usda new file mode 100755 index 0000000000..fb67f81c50 --- /dev/null +++ b/testsuite/common/usd/noisy_plane.usda @@ -0,0 +1,15 @@ +#usda 1.0 +( + defaultPrim = "NoisyPlane" +) + +def Bif "NoisyPlane" +{ + bool visibility = true + float3[] extent = [(-1,-1,-1), (1,1,1)] + string json = "/home/beauchc/dev/usdToArnold/data/bif/NoisyPlane.json" + float bifin:amplitude = .2 + float bifin:frequency = 7 + int bifin:subdivisions = 5000 +} + diff --git a/testsuite/common/usd/nurb.usda b/testsuite/common/usd/nurb.usda new file mode 100755 index 0000000000..7e8b61c1b7 --- /dev/null +++ b/testsuite/common/usd/nurb.usda @@ -0,0 +1,31 @@ +#usda 1.0 +( + defaultPrim = "nurbsSphere1" + endTimeCode = 1 + startTimeCode = 1 + upAxis = "Y" +) + +def NurbsPatch "nurbsSphere1" ( + kind = "component" +) +{ + uniform bool doubleSided = 1 + float3[] extent = [(-1.22641, -1, -1.22641), (1.22641, 1, 1.22641)] + point3f[] points = [(9.59647e-17, -1, -2.53162e-16), (0.199917, -1, -0.199917), (0.61643, -0.783612, -0.61643), (0.867202, 6.53539e-17, -0.867202), (0.61643, 0.783612, -0.61643), (0.199917, 1, -0.199917), (1.73997e-16, 1, -1.67996e-17), (9.59647e-17, -1, -2.53162e-16), (0.282725, -1, -6.22103e-17), (0.871764, -0.783612, 1.05062e-16), (1.22641, 1.22531e-17, 2.90111e-16), (0.871764, 0.783612, 3.07374e-16), (0.282725, 1, 1.95969e-16), (1.73997e-16, 1, -1.67996e-17), (9.59647e-17, -1, -2.53162e-16), (0.199917, -1, 0.199917), (0.61643, -0.783612, 0.61643), (0.867202, -4.08478e-17, 0.867202), (0.61643, 0.783612, 0.61643), (0.199917, 1, 0.199917), (1.73997e-16, 1, -1.67996e-17), (9.59647e-17, -1, -2.53162e-16), (1.1516e-16, -1, 0.282725), (1.99029e-16, -0.783612, 0.871764), (2.05191e-16, -6.28428e-17, 1.22641), (9.26813e-17, 0.783612, 0.871764), (-2.05545e-17, 1, 0.282725), (1.73997e-16, 1, -1.67996e-17), (9.59647e-17, -1, -2.53162e-16), (-0.199917, -1, 0.199917), (-0.61643, -0.783612, 0.61643), (-0.867202, -4.08478e-17, 0.867202), (-0.61643, 0.783612, 0.61643), (-0.199917, 1, 0.199917), (1.73997e-16, 1, -1.67996e-17), (9.59647e-17, -1, -2.53162e-16), (-0.282725, -1, 5.71917e-17), (-0.871764, -0.783612, 1.61111e-16), (-1.22641, 1.22531e-17, 2.19349e-16), (-0.871764, 0.783612, 1.50728e-16), (-0.282725, 1, 4.39418e-17), (1.73997e-16, 1, -1.67996e-17), (9.59647e-17, -1, -2.53162e-16), (-0.199917, -1, -0.199917), (-0.61643, -0.783612, -0.61643), (-0.867202, 6.53539e-17, -0.867202), (-0.61643, 0.783612, -0.61643), (-0.199917, 1, -0.199917), (1.73997e-16, 1, -1.67996e-17), (9.59647e-17, -1, -2.53162e-16), (-1.85086e-16, -1, -0.282725), (-4.14639e-16, -0.783612, -0.871764), (-5.08515e-16, 8.7349e-17, -1.22641), (-3.08292e-16, 0.783612, -0.871764), (-4.9371e-17, 1, -0.282725), (1.73997e-16, 1, -1.67996e-17), (9.59647e-17, -1, -2.53162e-16), (0.199917, -1, -0.199917), (0.61643, -0.783612, -0.61643), (0.867202, 6.53539e-17, -0.867202), (0.61643, 0.783612, -0.61643), (0.199917, 1, -0.199917), (1.73997e-16, 1, -1.67996e-17), (9.59647e-17, -1, -2.53162e-16), (0.282725, -1, -6.22103e-17), (0.871764, -0.783612, 1.05062e-16), (1.22641, 1.22531e-17, 2.90111e-16), (0.871764, 0.783612, 3.07374e-16), (0.282725, 1, 1.95969e-16), (1.73997e-16, 1, -1.67996e-17), (9.59647e-17, -1, -2.53162e-16), (0.199917, -1, 0.199917), (0.61643, -0.783612, 0.61643), (0.867202, -4.08478e-17, 0.867202), (0.61643, 0.783612, 0.61643), (0.199917, 1, 0.199917), (1.73997e-16, 1, -1.67996e-17)] + color3f[] primvars:displayColor = [(0.217638, 0.217638, 0.217638)] + float2[] primvars:st = [(0, 0), (0.166667, 0), (0.333333, 0), (0.5, 0), (0.666667, 0), (0.833333, 0), (1, 0), (0, 0.1), (0.166667, 0.1), (0.333333, 0.1), (0.5, 0.1), (0.666667, 0.1), (0.833333, 0.1), (1, 0.1), (0, 0.2), (0.166667, 0.2), (0.333333, 0.2), (0.5, 0.2), (0.666667, 0.2), (0.833333, 0.2), (1, 0.2), (0, 0.3), (0.166667, 0.3), (0.333333, 0.3), (0.5, 0.3), (0.666667, 0.3), (0.833333, 0.3), (1, 0.3), (0, 0.4), (0.166667, 0.4), (0.333333, 0.4), (0.5, 0.4), (0.666667, 0.4), (0.833333, 0.4), (1, 0.4), (0, 0.5), (0.166667, 0.5), (0.333333, 0.5), (0.5, 0.5), (0.666667, 0.5), (0.833333, 0.5), (1, 0.5), (0, 0.6), (0.166667, 0.6), (0.333333, 0.6), (0.5, 0.6), (0.666667, 0.6), (0.833333, 0.6), (1, 0.6), (0, 0.7), (0.166667, 0.7), (0.333333, 0.7), (0.5, 0.7), (0.666667, 0.7), (0.833333, 0.7), (1, 0.7), (0, 0.8), (0.166667, 0.8), (0.333333, 0.8), (0.5, 0.8), (0.666667, 0.8), (0.833333, 0.8), (1, 0.8), (0, 0.9), (0.166667, 0.9), (0.333333, 0.9), (0.5, 0.9), (0.666667, 0.9), (0.833333, 0.9), (1, 0.9), (0, 1), (0.166667, 1), (0.333333, 1), (0.5, 1), (0.666667, 1), (0.833333, 1), (1, 1)] ( + interpolation = "vertex" + ) + uniform token uForm = "open" + double[] uKnots = [0, 0, 0, 0, 1, 2, 3, 4, 4, 4, 4] + int uOrder = 4 + double2 uRange = (0, 4) + int uVertexCount = 7 + uniform token vForm = "periodic" + double[] vKnots = [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] + int vOrder = 4 + double2 vRange = (0, 8) + int vVertexCount = 11 +} + diff --git a/testsuite/common/usd/recursive_instances.usda b/testsuite/common/usd/recursive_instances.usda new file mode 100755 index 0000000000..5b444c6852 --- /dev/null +++ b/testsuite/common/usd/recursive_instances.usda @@ -0,0 +1,42 @@ +#usda 1.0 +( + defaultPrim = "root" +) + +class Xform "instance"( + instanceable = true +){ + float3 xformOp:translate= (0,.2,0) + float3 xformOp:rotateXYZ= (0,-50,0) + float3 xformOp:scale= (1.000000,1.000000,1.000000) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:scale", "xformOp:rotateXYZ"] + def "ref"( references = [ @./vespa.usda@ ] ){} +} + +class Xform "two_instances"( + instanceable = true +){ + float3 xformOp:translate= (0,0,0) + float3 xformOp:rotateXYZ= (0,0,0) + float3 xformOp:scale= (1.000000,1.000000,1.000000) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:scale", "xformOp:rotateXYZ"] + def "instance1"( references = ){ + float3 xformOp:translate= (0,0,-4.000000) + } + def "instance2"( references = ){ + float3 xformOp:translate= (0,0,-1.500000) + } +} + +def Xform "root" { + float3 xformOp:translate= (-1,0,0) + float3 xformOp:rotateXYZ= (0,-30,0) + float3 xformOp:scale= (1.000000,1.000000,1.000000) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:scale", "xformOp:rotateXYZ"] + def "a1"( references = ){ + float3 xformOp:translate= (-1,0,0) + } + def "a2"( references = ){ + float3 xformOp:translate= (1,0,0) + } +} diff --git a/testsuite/common/usd/refabc.usda b/testsuite/common/usd/refabc.usda new file mode 100755 index 0000000000..621eb940cf --- /dev/null +++ b/testsuite/common/usd/refabc.usda @@ -0,0 +1,9 @@ +#usda 1.0 +( + defaultPrim = "world" +) + +def Xform "world"( + add references = [ @./tree.abc@ ] +){ +} diff --git a/testsuite/common/usd/refbif.usda b/testsuite/common/usd/refbif.usda new file mode 100755 index 0000000000..07d5ff22a2 --- /dev/null +++ b/testsuite/common/usd/refbif.usda @@ -0,0 +1,41 @@ +#usda 1.0 +( + defaultPrim = "world" +) + +def Xform "world"{ + float3 xformOp:translate= (0,0,0) + float3 xformOp:rotateXYZ= (45,0,0) + float3 xformOp:scale= (.5,.5,.5) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:scale", "xformOp:rotateXYZ"] + def Xform "left"{ + float3 xformOp:translate= (-2,0,0) + uniform token[] xformOpOrder = ["xformOp:translate"] + def Bif "bif"( + references = @./bif.usda@ + ){ + float bifchannel:velocityScale = .5 + float bifin:weight = -.2 + } + } + def Xform "middle"{ + float3 xformOp:translate= (0,0,0) + uniform token[] xformOpOrder = ["xformOp:translate"] + def Bif "bif"( + references = @./bif.usda@ + ){ + float bifchannel:velocityScale = 0 + float bifin:weight = -.5 + } + } + def Xform "right"{ + float3 xformOp:translate= (2,0,0) + uniform token[] xformOpOrder = ["xformOp:translate"] + def Bif "bif"( + references = @./bif.usda@ + ){ + float bifchannel:velocityScale = .2 + bool bifin:condition = true + } + } +} diff --git a/testsuite/common/usd/refbifplane.usda b/testsuite/common/usd/refbifplane.usda new file mode 100755 index 0000000000..5881675f79 --- /dev/null +++ b/testsuite/common/usd/refbifplane.usda @@ -0,0 +1,85 @@ +#usda 1.0 +( + defaultPrim = "world" +) + +def Xform "world"{ + def Xform "row1"{ + float3 xformOp:translate= (0,1,0) + float3 xformOp:rotateXYZ= (55,0,0) + float3 xformOp:scale= (.5,.5,.5) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:scale", "xformOp:rotateXYZ"] + def Xform "topleft"{ + float3 xformOp:translate= (-2.5,0,0) + uniform token[] xformOpOrder = ["xformOp:translate"] + def Bif "bif"( + references = @./noisy_plane.usda@ + ){ + float bifin:amplitude = .1 + float bifin:frequency = 1.5 + int bifin:subdivisions = 200 + } + } + def Xform "topmiddle"{ + float3 xformOp:translate= (0,0,0) + uniform token[] xformOpOrder = ["xformOp:translate"] + def Bif "bif"( + references = @./noisy_plane.usda@ + ){ + float bifin:amplitude = .2 + float bifin:frequency = 3.3 + int bifin:subdivisions = 50 + } + } + def Xform "topright"{ + float3 xformOp:translate= (2.5,0,0) + uniform token[] xformOpOrder = ["xformOp:translate"] + def Bif "bif"( + references = @./noisy_plane.usda@ + ){ + float bifin:amplitude = .005 + float bifin:frequency = 30 + int bifin:subdivisions = 1000 + } + } + } + def Xform "row2"{ + float3 xformOp:translate= (0,0,0) + float3 xformOp:rotateXYZ= (55,0,0) + float3 xformOp:scale= (.5,.5,.5) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:scale", "xformOp:rotateXYZ"] + def Xform "bottomleft"{ + float3 xformOp:translate= (-2.5,0,0) + uniform token[] xformOpOrder = ["xformOp:translate"] + def Bif "bif"( + references = @./noisy_plane.usda@ + ){ + float bifin:amplitude = .1 + float bifin:frequency = 2 + int bifin:subdivisions = 20 + } + } + def Xform "bottommiddle"{ + float3 xformOp:translate= (0,0,0) + uniform token[] xformOpOrder = ["xformOp:translate"] + def Bif "bif"( + references = @./noisy_plane.usda@ + ){ + float bifin:amplitude = .25 + float bifin:frequency = 1 + int bifin:subdivisions = 300 + } + } + def Xform "bottomright"{ + float3 xformOp:translate= (2.5,0,0) + uniform token[] xformOpOrder = ["xformOp:translate"] + def Bif "bif"( + references = @./noisy_plane.usda@ + ){ + float bifin:amplitude = .05 + float bifin:frequency = 6 + int bifin:subdivisions = 500 + } + } + } +} diff --git a/testsuite/common/usd/refinstances.usda b/testsuite/common/usd/refinstances.usda new file mode 100755 index 0000000000..8da5d07e2d --- /dev/null +++ b/testsuite/common/usd/refinstances.usda @@ -0,0 +1,10 @@ +#usda 1.0 +( + subLayers = [ @./instances.usda@ ] + defaultPrim = "root" +) + +over "root" +{ + def "mxlook" ( references = [ @./instances.mtlx@ ] ) {} +} diff --git a/testsuite/common/usd/refplanes.usda b/testsuite/common/usd/refplanes.usda new file mode 100755 index 0000000000..cbd7dd973a --- /dev/null +++ b/testsuite/common/usd/refplanes.usda @@ -0,0 +1,34 @@ +#usda 1.0 +( + defaultPrim = "world" +) + +def Xform "world"( + references = @./grid.usda@ +){ + float3 xformOp:scale= (.3, .3, .3) + uniform token[] xformOpOrder = ["xformOp:scale"] + over "row1"{ + over "col1"( add references = @./bif.usda@ ){ + float bifchannel:velocityScale = .25 + } + over "col2"( add references = @./bif.usda@ ){ + float bifchannel:velocityScale = 0 + float bifin:weight = -.3 + } + over "col3"( add references = @./sphere.usda@ ){} + over "col4"( add references = @./sphere.usda@ ){} + } + over "row2"{ + over "col1"( add references = @./sphere.usda@ ){} + over "col2"( add references = @./cube.usda@ ){} + over "col3"( add references = @./mesh.usda@ ){} + over "col4"( add references = @./sphere.usda@ ){} + } + over "row3"{ + over "col1"( add references = @./sphere.usda@ ){} + over "col2"( add references = @./sphere.usda@ ){} + over "col3"( add references = @./sphere.usda@ ){} + over "col4"( add references = @./sphere.usda@ ){} + } +} diff --git a/testsuite/common/usd/refsven.usda b/testsuite/common/usd/refsven.usda new file mode 100755 index 0000000000..26e0a8ece6 --- /dev/null +++ b/testsuite/common/usd/refsven.usda @@ -0,0 +1,20 @@ +#usda 1.0 +( + defaultPrim = "root" +) + +def Xform "root"{ + def Xform "sven_group"( + add references = [ @./sven.usda@ ] + ){ + float3 xformOp:translate= (-.65,0,0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + def Xform "sven_group2"( + add references = [ @./sven.usda@ ] + ){ + float3 xformOp:translate= (.65,0,0) + float3 xformOp:rotateXYZ= (0,180,0) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } +} diff --git a/testsuite/common/usd/refvespa.usda b/testsuite/common/usd/refvespa.usda new file mode 100755 index 0000000000..03b8898d4b --- /dev/null +++ b/testsuite/common/usd/refvespa.usda @@ -0,0 +1,29 @@ +#usda 1.0 +( + defaultPrim = "root" +) + +class Xform "vespa"( + instanceable = true +){ + float3 xformOp:translate= (0,.2,0) + uniform token[] xformOpOrder = ["xformOp:translate"] + def "vespa1"( + references = [ @./vespa.usda@ ] + ){} +} + +def Xform "root" { + def "a"( references = ){ + float3 xformOp:translate= (.75,0,0) + float3 xformOp:rotateXYZ= (0,-50,0) + float3 xformOp:scale= (1,1,1) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:scale", "xformOp:rotateXYZ"] + } + def "b"( references = ){ + float3 xformOp:translate= (-.75,0,0) + float3 xformOp:rotateXYZ= (0,-30,0) + float3 xformOp:scale= (1,1,1) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:scale", "xformOp:rotateXYZ"] + } +} diff --git a/testsuite/common/usd/row.usda b/testsuite/common/usd/row.usda new file mode 100755 index 0000000000..9c10b201a5 --- /dev/null +++ b/testsuite/common/usd/row.usda @@ -0,0 +1,24 @@ +#usda 1.0 +( + defaultPrim = "row" +) + +def Xform "row"{ + def Xform "col1"{ + float3 xformOp:translate= (-4.5,0,0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + def Xform "col2"{ + float3 xformOp:translate= (-1.5,0,0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + def Xform "col3"{ + float3 xformOp:translate= (1.5,0,0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + def Xform "col4"{ + float3 xformOp:translate= (4.5,0,0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } +} + diff --git a/testsuite/common/usd/sphere.usda b/testsuite/common/usd/sphere.usda new file mode 100755 index 0000000000..9347d73874 --- /dev/null +++ b/testsuite/common/usd/sphere.usda @@ -0,0 +1,8 @@ +#usda 1.0 +( + defaultPrim = "sphere" +) + +def Sphere "sphere" +{ +} diff --git a/testsuite/common/usd/tmp.usda b/testsuite/common/usd/tmp.usda new file mode 100755 index 0000000000..4fcae1703a --- /dev/null +++ b/testsuite/common/usd/tmp.usda @@ -0,0 +1,8 @@ +#usda 1.0 +( + defaultPrim = "sphere" +) + +over "sphere"{ + double radius = .1 +} diff --git a/testsuite/common/usd/tree.abc b/testsuite/common/usd/tree.abc new file mode 100755 index 0000000000..d4261cb02b Binary files /dev/null and b/testsuite/common/usd/tree.abc differ diff --git a/testsuite/common/usd/tree.usd b/testsuite/common/usd/tree.usd new file mode 100755 index 0000000000..666d244c4c Binary files /dev/null and b/testsuite/common/usd/tree.usd differ diff --git a/testsuite/common/valgrind.supp b/testsuite/common/valgrind.supp new file mode 100755 index 0000000000..6915f08d6f --- /dev/null +++ b/testsuite/common/valgrind.supp @@ -0,0 +1,10 @@ +{ + + Memcheck:Free + fun:free + obj:/lib64/libc-2.5.so + obj:/lib64/libc-2.5.so + fun:_vgnU_freeres + fun:exit + fun:(below main) +} diff --git a/testsuite/common/vlgrnd-xml.awk b/testsuite/common/vlgrnd-xml.awk new file mode 100755 index 0000000000..2122a2686d --- /dev/null +++ b/testsuite/common/vlgrnd-xml.awk @@ -0,0 +1,11 @@ +# +# this is an awk program which will attempt to parse +# valgrind output +# +# bytes_lost_def +# bytes_lost_prob +# bytes_lost +BEGIN { } # do something here +//,/<\/leakedbytes>/ { printf $1; } +END { } + diff --git a/testsuite/common/vlgrnd.awk b/testsuite/common/vlgrnd.awk new file mode 100755 index 0000000000..003f6e7121 --- /dev/null +++ b/testsuite/common/vlgrnd.awk @@ -0,0 +1,34 @@ +# +# this is an awk program which will attempt to parse +# valgrind output +# +# bld -- bytes lost definitely +# blp -- bytes lost probably +# bytes_lost +# numm -- number of mallocs +# numf -- number of frees +BEGIN { # do something here +} +/definitely lost:/ { bld += $4 * $7; } +/possibly lost:/ { blp += $4 * $7; } +/ERROR SUMMARY:/ { errs += $4; } +END { + printf("Valgrind summary:\n"); + printf(" Total number of errors: %d\n", errs); + printf(" Bytes definitely lost: %d\n", bld); + printf(" Bytes possibly lost: %d\n", blp); + + if ( errs != 0 ) + { + exit 1; + } + else { + if ( bld!=0 || blp!=0) + { + exit 2; + } + } + + +} + diff --git a/testsuite/common/vlgrnd.supp b/testsuite/common/vlgrnd.supp new file mode 100755 index 0000000000..6689b09e85 --- /dev/null +++ b/testsuite/common/vlgrnd.supp @@ -0,0 +1,222 @@ +# +# suppression file for the testsuite +# +# +# -- this hides the memory leak that seems to be +# -- inside the pthread-mutex call +{ + CritSecLeak + Memcheck:Leak + fun:_vgrZU_libcZdsoZa_malloc + fun:bmalloc_func + fun:AiCritSecInit_linux +} +# +# -- this hides a memory leak when launching +# -- multiple threads +{ + PthreadLaunchLeak + Memcheck:Leak + fun:*calloc + fun:_dl_allocate_tls + fun:pthread_create + fun:AiThreadCreate_linux +} +{ + JumpOnUnintializedLoca_dlopen + Memcheck:Cond + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/tls/libc-2.3.4.so + obj:/lib/ld-2.3.4.so + fun:_dl_open + obj:/lib/libdl-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/libdl-2.3.4.so + fun:dlopen +} +{ + JumpOnUnintializedLoca_dlopen + Memcheck:Cond + obj:/lib/ld-2.3.4.so + obj:/lib/tls/libc-2.3.4.so + obj:/lib/ld-2.3.4.so + fun:_dl_open + obj:/lib/libdl-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/libdl-2.3.4.so + fun:dlopen +} +{ + JumpOnUnintializedLoca_dlopen + Memcheck:Cond + obj:/lib/ld-2.3.4.so + obj:/lib/tls/libc-2.3.4.so + obj:/lib/ld-2.3.4.so + fun:_dl_open + obj:/lib/libdl-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/libdl-2.3.4.so + fun:dlopen +} +{ + DLOpenMemLeak + Memcheck:Leak + fun:*calloc + obj:/lib/libdl-2.3.4.so + fun:dlopen +} +{ + PthreadMemoryLeak + Memcheck:Leak + fun:*calloc + fun:_dl_allocate_tls + fun:pthread_create + fun:AiThreadCreate_linux +} +{ + dlopen + Memcheck:Cond + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/tls/libc-2.3.4.so + obj:/lib/ld-2.3.4.so + fun:_dl_open + obj:/lib/libdl-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/libdl-2.3.4.so + fun:dlopen +} +{ + dlopenagain + Memcheck:Cond + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/tls/libc-2.3.4.so + obj:/lib/ld-2.3.4.so + fun:_dl_open + obj:/lib/libdl-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/libdl-2.3.4.so + fun:dlopen +} +{ + moredlopen + Memcheck:Cond + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/tls/libc-2.3.4.so + obj:/lib/ld-2.3.4.so + fun:_dl_open + obj:/lib/libdl-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/libdl-2.3.4.so + fun:dlopen +} +{ + dlopenagain2 + Memcheck:Cond + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/tls/libc-2.3.4.so + obj:/lib/ld-2.3.4.so + fun:_dl_open + obj:/lib/libdl-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/libdl-2.3.4.so + fun:dlopen +} +{ + dlopenagain3 + Memcheck:Addr4 + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/tls/libc-2.3.4.so + obj:/lib/ld-2.3.4.so + fun:_dl_open + obj:/lib/libdl-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/libdl-2.3.4.so + fun:dlopen + fun:AiLibraryLoad_linux +} +{ + dlsymproblem + Memcheck:Addr4 + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/tls/libc-2.3.4.so + fun:_dl_sym + obj:/lib/libdl-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/libdl-2.3.4.so + fun:dlsym + fun:AiLibrarySymbol_linux +} +{ + dlsym_problem_2 + Memcheck:Cond + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/tls/libc-2.3.4.so + fun:_dl_sym + obj:/lib/libdl-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/libdl-2.3.4.so + fun:dlsym + fun:AiLibrarySymbol_linux +} +{ + dlopen_more_problems + Memcheck:Addr4 + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/tls/libc-2.3.4.so + obj:/lib/ld-2.3.4.so + fun:_dl_open + obj:/lib/libdl-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/libdl-2.3.4.so + fun:dlopen + fun:AiLibraryLoad_linux +} +{ + dlopen_leak + Memcheck:Leak + fun:*calloc + obj:/lib/libdl-2.3.4.so + fun:dlopen +} +{ + another_dlopen_problem + Memcheck:Addr4 + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/tls/libc-2.3.4.so + obj:/lib/ld-2.3.4.so + fun:_dl_open + obj:/lib/libdl-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/libdl-2.3.4.so + fun:dlopen + fun:AiLibraryLoad_linux +} +{ + anotherdlopenerror + Memcheck:Addr4 + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/tls/libc-2.3.4.so + obj:/lib/ld-2.3.4.so + fun:_dl_open + obj:/lib/libdl-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/libdl-2.3.4.so + fun:dlopen + fun:AiLibraryLoad_linux +} + diff --git a/testsuite/groups b/testsuite/groups new file mode 100755 index 0000000000..7121fc38db --- /dev/null +++ b/testsuite/groups @@ -0,0 +1,50 @@ +# groups +# +# This file maps all testgroups (elements on the left hand side) with their respective tests. You can also +# have a local file (groups.local) with the same format, where you can override any group in this file. +# +# Notes: +# - Tests can be listed in as many groups as needed. +# - Groups can be recursively added to other groups. +# - A special group called 'ignore' contains tests that will never be run (you can use it to temporarily +# disable some tests or groups) +# - There is a special group per supported OS, where you can add tests that will ONLY be run for that +# specific OS (linux, darwin, windows). +# +# The following command will find all tests that contain a specific keyword (e.g. polymesh): +# +# > grep polymesh testsuite/test*/data/*.ass | cut -f 2 -d '/' | sort -u +# +# This can help in making sure that a group contains almost all relevant tests. Note that it's still +# possible to miss some tests (like with procedurally generated content) or to find things you don't want +# (such as this_is_not_a_polymesh being returned for tests that use polymesh). + + +################################# +# PLATFORM_SPECIFIC TEST GROUPS # +################################# + +# NOTE: Try to avoid adding platform-specific tests that output images. +# Having such tests makes updating image references on a single platform unsafe. + +# Only executed on Windows +windows: + +# Only executed on Linux +linux: + +# Only executed on Darwin +darwin: + +####################### +# SPECIAL TEST GROUPS # +####################### + +# Tests in this group will never be executed (you can use it to temporarily disable some tests and/or groups) +ignore: test_0011 test_0016 + + +############################ +# USER-DEFINED TEST GROUPS # +############################ + diff --git a/testsuite/test_0000/README b/testsuite/test_0000/README new file mode 100755 index 0000000000..56baed450e --- /dev/null +++ b/testsuite/test_0000/README @@ -0,0 +1,4 @@ +Test Mesh and Xform + +author: sebastien ortega + diff --git a/testsuite/test_0000/data/sphere.usd b/testsuite/test_0000/data/sphere.usd new file mode 100755 index 0000000000..30c9491ffe --- /dev/null +++ b/testsuite/test_0000/data/sphere.usd @@ -0,0 +1,332 @@ +#usda 1.0 +( + endTimeCode = 0 + startTimeCode = 0 + upAxis = "Z" +) + +def Xform "ExampleModelingVariants" ( + kind = "component" + variants = { + string modelingVariant = "Sphere" + } + add variantSets = "modelingVariant" +) +{ + float3[] extentsHint = [(-1.5, -1, -1.5), (1.5, 1, 1.5)] + + def Xform "Geom" + { + def Mesh "pSphere1" ( + hidden = true + ) + { + float3[] extent = [(-1, -1, -1), (1, 1, 1)] + int[] faceVertexCounts = [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3] + int[] faceVertexIndices = [0, 1, 21, 20, 1, 2, 22, 21, 2, 3, 23, 22, 3, 4, 24, 23, 4, 5, 25, 24, 5, 6, 26, 25, 6, 7, 27, 26, 7, 8, 28, 27, 8, 9, 29, 28, 9, 10, 30, 29, 10, 11, 31, 30, 11, 12, 32, 31, 12, 13, 33, 32, 13, 14, 34, 33, 14, 15, 35, 34, 15, 16, 36, 35, 16, 17, 37, 36, 17, 18, 38, 37, 18, 19, 39, 38, 19, 0, 20, 39, 20, 21, 41, 40, 21, 22, 42, 41, 22, 23, 43, 42, 23, 24, 44, 43, 24, 25, 45, 44, 25, 26, 46, 45, 26, 27, 47, 46, 27, 28, 48, 47, 28, 29, 49, 48, 29, 30, 50, 49, 30, 31, 51, 50, 31, 32, 52, 51, 32, 33, 53, 52, 33, 34, 54, 53, 34, 35, 55, 54, 35, 36, 56, 55, 36, 37, 57, 56, 37, 38, 58, 57, 38, 39, 59, 58, 39, 20, 40, 59, 40, 41, 61, 60, 41, 42, 62, 61, 42, 43, 63, 62, 43, 44, 64, 63, 44, 45, 65, 64, 45, 46, 66, 65, 46, 47, 67, 66, 47, 48, 68, 67, 48, 49, 69, 68, 49, 50, 70, 69, 50, 51, 71, 70, 51, 52, 72, 71, 52, 53, 73, 72, 53, 54, 74, 73, 54, 55, 75, 74, 55, 56, 76, 75, 56, 57, 77, 76, 57, 58, 78, 77, 58, 59, 79, 78, 59, 40, 60, 79, 60, 61, 81, 80, 61, 62, 82, 81, 62, 63, 83, 82, 63, 64, 84, 83, 64, 65, 85, 84, 65, 66, 86, 85, 66, 67, 87, 86, 67, 68, 88, 87, 68, 69, 89, 88, 69, 70, 90, 89, 70, 71, 91, 90, 71, 72, 92, 91, 72, 73, 93, 92, 73, 74, 94, 93, 74, 75, 95, 94, 75, 76, 96, 95, 76, 77, 97, 96, 77, 78, 98, 97, 78, 79, 99, 98, 79, 60, 80, 99, 80, 81, 101, 100, 81, 82, 102, 101, 82, 83, 103, 102, 83, 84, 104, 103, 84, 85, 105, 104, 85, 86, 106, 105, 86, 87, 107, 106, 87, 88, 108, 107, 88, 89, 109, 108, 89, 90, 110, 109, 90, 91, 111, 110, 91, 92, 112, 111, 92, 93, 113, 112, 93, 94, 114, 113, 94, 95, 115, 114, 95, 96, 116, 115, 96, 97, 117, 116, 97, 98, 118, 117, 98, 99, 119, 118, 99, 80, 100, 119, 100, 101, 121, 120, 101, 102, 122, 121, 102, 103, 123, 122, 103, 104, 124, 123, 104, 105, 125, 124, 105, 106, 126, 125, 106, 107, 127, 126, 107, 108, 128, 127, 108, 109, 129, 128, 109, 110, 130, 129, 110, 111, 131, 130, 111, 112, 132, 131, 112, 113, 133, 132, 113, 114, 134, 133, 114, 115, 135, 134, 115, 116, 136, 135, 116, 117, 137, 136, 117, 118, 138, 137, 118, 119, 139, 138, 119, 100, 120, 139, 120, 121, 141, 140, 121, 122, 142, 141, 122, 123, 143, 142, 123, 124, 144, 143, 124, 125, 145, 144, 125, 126, 146, 145, 126, 127, 147, 146, 127, 128, 148, 147, 128, 129, 149, 148, 129, 130, 150, 149, 130, 131, 151, 150, 131, 132, 152, 151, 132, 133, 153, 152, 133, 134, 154, 153, 134, 135, 155, 154, 135, 136, 156, 155, 136, 137, 157, 156, 137, 138, 158, 157, 138, 139, 159, 158, 139, 120, 140, 159, 140, 141, 161, 160, 141, 142, 162, 161, 142, 143, 163, 162, 143, 144, 164, 163, 144, 145, 165, 164, 145, 146, 166, 165, 146, 147, 167, 166, 147, 148, 168, 167, 148, 149, 169, 168, 149, 150, 170, 169, 150, 151, 171, 170, 151, 152, 172, 171, 152, 153, 173, 172, 153, 154, 174, 173, 154, 155, 175, 174, 155, 156, 176, 175, 156, 157, 177, 176, 157, 158, 178, 177, 158, 159, 179, 178, 159, 140, 160, 179, 160, 161, 181, 180, 161, 162, 182, 181, 162, 163, 183, 182, 163, 164, 184, 183, 164, 165, 185, 184, 165, 166, 186, 185, 166, 167, 187, 186, 167, 168, 188, 187, 168, 169, 189, 188, 169, 170, 190, 189, 170, 171, 191, 190, 171, 172, 192, 191, 172, 173, 193, 192, 173, 174, 194, 193, 174, 175, 195, 194, 175, 176, 196, 195, 176, 177, 197, 196, 177, 178, 198, 197, 178, 179, 199, 198, 179, 160, 180, 199, 180, 181, 201, 200, 181, 182, 202, 201, 182, 183, 203, 202, 183, 184, 204, 203, 184, 185, 205, 204, 185, 186, 206, 205, 186, 187, 207, 206, 187, 188, 208, 207, 188, 189, 209, 208, 189, 190, 210, 209, 190, 191, 211, 210, 191, 192, 212, 211, 192, 193, 213, 212, 193, 194, 214, 213, 194, 195, 215, 214, 195, 196, 216, 215, 196, 197, 217, 216, 197, 198, 218, 217, 198, 199, 219, 218, 199, 180, 200, 219, 200, 201, 221, 220, 201, 202, 222, 221, 202, 203, 223, 222, 203, 204, 224, 223, 204, 205, 225, 224, 205, 206, 226, 225, 206, 207, 227, 226, 207, 208, 228, 227, 208, 209, 229, 228, 209, 210, 230, 229, 210, 211, 231, 230, 211, 212, 232, 231, 212, 213, 233, 232, 213, 214, 234, 233, 214, 215, 235, 234, 215, 216, 236, 235, 216, 217, 237, 236, 217, 218, 238, 237, 218, 219, 239, 238, 219, 200, 220, 239, 220, 221, 241, 240, 221, 222, 242, 241, 222, 223, 243, 242, 223, 224, 244, 243, 224, 225, 245, 244, 225, 226, 246, 245, 226, 227, 247, 246, 227, 228, 248, 247, 228, 229, 249, 248, 229, 230, 250, 249, 230, 231, 251, 250, 231, 232, 252, 251, 232, 233, 253, 252, 233, 234, 254, 253, 234, 235, 255, 254, 235, 236, 256, 255, 236, 237, 257, 256, 237, 238, 258, 257, 238, 239, 259, 258, 239, 220, 240, 259, 240, 241, 261, 260, 241, 242, 262, 261, 242, 243, 263, 262, 243, 244, 264, 263, 244, 245, 265, 264, 245, 246, 266, 265, 246, 247, 267, 266, 247, 248, 268, 267, 248, 249, 269, 268, 249, 250, 270, 269, 250, 251, 271, 270, 251, 252, 272, 271, 252, 253, 273, 272, 253, 254, 274, 273, 254, 255, 275, 274, 255, 256, 276, 275, 256, 257, 277, 276, 257, 258, 278, 277, 258, 259, 279, 278, 259, 240, 260, 279, 260, 261, 281, 280, 261, 262, 282, 281, 262, 263, 283, 282, 263, 264, 284, 283, 264, 265, 285, 284, 265, 266, 286, 285, 266, 267, 287, 286, 267, 268, 288, 287, 268, 269, 289, 288, 269, 270, 290, 289, 270, 271, 291, 290, 271, 272, 292, 291, 272, 273, 293, 292, 273, 274, 294, 293, 274, 275, 295, 294, 275, 276, 296, 295, 276, 277, 297, 296, 277, 278, 298, 297, 278, 279, 299, 298, 279, 260, 280, 299, 280, 281, 301, 300, 281, 282, 302, 301, 282, 283, 303, 302, 283, 284, 304, 303, 284, 285, 305, 304, 285, 286, 306, 305, 286, 287, 307, 306, 287, 288, 308, 307, 288, 289, 309, 308, 289, 290, 310, 309, 290, 291, 311, 310, 291, 292, 312, 311, 292, 293, 313, 312, 293, 294, 314, 313, 294, 295, 315, 314, 295, 296, 316, 315, 296, 297, 317, 316, 297, 298, 318, 317, 298, 299, 319, 318, 299, 280, 300, 319, 300, 301, 321, 320, 301, 302, 322, 321, 302, 303, 323, 322, 303, 304, 324, 323, 304, 305, 325, 324, 305, 306, 326, 325, 306, 307, 327, 326, 307, 308, 328, 327, 308, 309, 329, 328, 309, 310, 330, 329, 310, 311, 331, 330, 311, 312, 332, 331, 312, 313, 333, 332, 313, 314, 334, 333, 314, 315, 335, 334, 315, 316, 336, 335, 316, 317, 337, 336, 317, 318, 338, 337, 318, 319, 339, 338, 319, 300, 320, 339, 320, 321, 341, 340, 321, 322, 342, 341, 322, 323, 343, 342, 323, 324, 344, 343, 324, 325, 345, 344, 325, 326, 346, 345, 326, 327, 347, 346, 327, 328, 348, 347, 328, 329, 349, 348, 329, 330, 350, 349, 330, 331, 351, 350, 331, 332, 352, 351, 332, 333, 353, 352, 333, 334, 354, 353, 334, 335, 355, 354, 335, 336, 356, 355, 336, 337, 357, 356, 337, 338, 358, 357, 338, 339, 359, 358, 339, 320, 340, 359, 340, 341, 361, 360, 341, 342, 362, 361, 342, 343, 363, 362, 343, 344, 364, 363, 344, 345, 365, 364, 345, 346, 366, 365, 346, 347, 367, 366, 347, 348, 368, 367, 348, 349, 369, 368, 349, 350, 370, 369, 350, 351, 371, 370, 351, 352, 372, 371, 352, 353, 373, 372, 353, 354, 374, 373, 354, 355, 375, 374, 355, 356, 376, 375, 356, 357, 377, 376, 357, 358, 378, 377, 358, 359, 379, 378, 359, 340, 360, 379, 1, 0, 380, 2, 1, 380, 3, 2, 380, 4, 3, 380, 5, 4, 380, 6, 5, 380, 7, 6, 380, 8, 7, 380, 9, 8, 380, 10, 9, 380, 11, 10, 380, 12, 11, 380, 13, 12, 380, 14, 13, 380, 15, 14, 380, 16, 15, 380, 17, 16, 380, 18, 17, 380, 19, 18, 380, 0, 19, 380, 360, 361, 381, 361, 362, 381, 362, 363, 381, 363, 364, 381, 364, 365, 381, 365, 366, 381, 366, 367, 381, 367, 368, 381, 368, 369, 381, 369, 370, 381, 370, 371, 381, 371, 372, 381, 372, 373, 381, 373, 374, 381, 374, 375, 381, 375, 376, 381, 376, 377, 381, 377, 378, 381, 378, 379, 381, 379, 360, 381] + token interpolateBoundary = "edgeAndCorner" + uniform token orientation = "rightHanded" + float3[] points = [(0.148778, -0.987688, -0.0483409), (0.126558, -0.987688, -0.0919499), (0.0919499, -0.987688, -0.126558), (0.0483409, -0.987688, -0.148778), (0, -0.987688, -0.156435), (-0.0483409, -0.987688, -0.148778), (-0.0919499, -0.987688, -0.126558), (-0.126558, -0.987688, -0.0919499), (-0.148778, -0.987688, -0.0483409), (-0.156435, -0.987688, 0), (-0.148778, -0.987688, 0.0483409), (-0.126558, -0.987688, 0.0919499), (-0.0919499, -0.987688, 0.126558), (-0.0483409, -0.987688, 0.148778), (-4.66211e-09, -0.987688, 0.156434), (0.0483409, -0.987688, 0.148778), (0.0919499, -0.987688, 0.126558), (0.126558, -0.987688, 0.0919499), (0.148778, -0.987688, 0.0483409), (0.156434, -0.987688, 0), (0.293893, -0.951057, -0.0954916), (0.25, -0.951057, -0.181636), (0.181636, -0.951057, -0.25), (0.0954916, -0.951057, -0.293893), (0, -0.951057, -0.309017), (-0.0954916, -0.951057, -0.293893), (-0.181636, -0.951057, -0.25), (-0.25, -0.951057, -0.181636), (-0.293893, -0.951057, -0.0954915), (-0.309017, -0.951057, 0), (-0.293893, -0.951057, 0.0954915), (-0.25, -0.951057, 0.181636), (-0.181636, -0.951057, 0.25), (-0.0954915, -0.951057, 0.293893), (-9.20942e-09, -0.951057, 0.309017), (0.0954915, -0.951057, 0.293893), (0.181636, -0.951057, 0.25), (0.25, -0.951057, 0.181636), (0.293893, -0.951057, 0.0954915), (0.309017, -0.951057, 0), (0.431771, -0.891007, -0.140291), (0.367286, -0.891007, -0.266849), (0.266849, -0.891007, -0.367286), (0.140291, -0.891007, -0.431771), (0, -0.891007, -0.453991), (-0.140291, -0.891007, -0.431771), (-0.266849, -0.891007, -0.367286), (-0.367286, -0.891007, -0.266849), (-0.431771, -0.891007, -0.140291), (-0.453991, -0.891007, 0), (-0.431771, -0.891007, 0.140291), (-0.367286, -0.891007, 0.266849), (-0.266849, -0.891007, 0.367286), (-0.140291, -0.891007, 0.431771), (-1.353e-08, -0.891007, 0.453991), (0.140291, -0.891007, 0.431771), (0.266849, -0.891007, 0.367286), (0.367286, -0.891007, 0.266849), (0.431771, -0.891007, 0.140291), (0.453991, -0.891007, 0), (0.559017, -0.809017, -0.181636), (0.475529, -0.809017, -0.345492), (0.345492, -0.809017, -0.475529), (0.181636, -0.809017, -0.559017), (0, -0.809017, -0.587786), (-0.181636, -0.809017, -0.559017), (-0.345492, -0.809017, -0.475528), (-0.475528, -0.809017, -0.345492), (-0.559017, -0.809017, -0.181636), (-0.587785, -0.809017, 0), (-0.559017, -0.809017, 0.181636), (-0.475528, -0.809017, 0.345492), (-0.345492, -0.809017, 0.475528), (-0.181636, -0.809017, 0.559017), (-1.75174e-08, -0.809017, 0.587785), (0.181636, -0.809017, 0.559017), (0.345491, -0.809017, 0.475528), (0.475528, -0.809017, 0.345492), (0.559017, -0.809017, 0.181636), (0.587785, -0.809017, 0), (0.672499, -0.707107, -0.218508), (0.572062, -0.707107, -0.415627), (0.415627, -0.707107, -0.572062), (0.218508, -0.707107, -0.672499), (0, -0.707107, -0.707107), (-0.218508, -0.707107, -0.672499), (-0.415627, -0.707107, -0.572062), (-0.572062, -0.707107, -0.415627), (-0.672499, -0.707107, -0.218508), (-0.707107, -0.707107, 0), (-0.672499, -0.707107, 0.218508), (-0.572062, -0.707107, 0.415627), (-0.415627, -0.707107, 0.572061), (-0.218508, -0.707107, 0.672499), (-2.10734e-08, -0.707107, 0.707107), (0.218508, -0.707107, 0.672499), (0.415627, -0.707107, 0.572061), (0.572061, -0.707107, 0.415627), (0.672499, -0.707107, 0.218508), (0.707107, -0.707107, 0), (0.769421, -0.587785, -0.25), (0.654509, -0.587785, -0.475529), (0.475529, -0.587785, -0.654509), (0.25, -0.587785, -0.769421), (0, -0.587785, -0.809017), (-0.25, -0.587785, -0.769421), (-0.475528, -0.587785, -0.654509), (-0.654509, -0.587785, -0.475528), (-0.769421, -0.587785, -0.25), (-0.809017, -0.587785, 0), (-0.769421, -0.587785, 0.25), (-0.654509, -0.587785, 0.475528), (-0.475528, -0.587785, 0.654509), (-0.25, -0.587785, 0.769421), (-2.41106e-08, -0.587785, 0.809017), (0.25, -0.587785, 0.769421), (0.475528, -0.587785, 0.654509), (0.654509, -0.587785, 0.475528), (0.769421, -0.587785, 0.25), (0.809017, -0.587785, 0), (0.847398, -0.453991, -0.275336), (0.72084, -0.453991, -0.523721), (0.523721, -0.453991, -0.72084), (0.275336, -0.453991, -0.847398), (0, -0.453991, -0.891007), (-0.275336, -0.453991, -0.847398), (-0.523721, -0.453991, -0.72084), (-0.72084, -0.453991, -0.523721), (-0.847398, -0.453991, -0.275336), (-0.891007, -0.453991, 0), (-0.847398, -0.453991, 0.275336), (-0.72084, -0.453991, 0.523721), (-0.523721, -0.453991, 0.72084), (-0.275336, -0.453991, 0.847398), (-2.65541e-08, -0.453991, 0.891007), (0.275336, -0.453991, 0.847398), (0.523721, -0.453991, 0.72084), (0.720839, -0.453991, 0.523721), (0.847398, -0.453991, 0.275336), (0.891007, -0.453991, 0), (0.904509, -0.309017, -0.293893), (0.769421, -0.309017, -0.559017), (0.559017, -0.309017, -0.769421), (0.293893, -0.309017, -0.904509), (0, -0.309017, -0.951057), (-0.293893, -0.309017, -0.904509), (-0.559017, -0.309017, -0.769421), (-0.769421, -0.309017, -0.559017), (-0.904509, -0.309017, -0.293893), (-0.951057, -0.309017, 0), (-0.904509, -0.309017, 0.293893), (-0.769421, -0.309017, 0.559017), (-0.559017, -0.309017, 0.769421), (-0.293893, -0.309017, 0.904509), (-2.83437e-08, -0.309017, 0.951057), (0.293893, -0.309017, 0.904509), (0.559017, -0.309017, 0.769421), (0.769421, -0.309017, 0.559017), (0.904509, -0.309017, 0.293893), (0.951057, -0.309017, 0), (0.939348, -0.156434, -0.305213), (0.799057, -0.156434, -0.580549), (0.580549, -0.156434, -0.799057), (0.305213, -0.156434, -0.939348), (0, -0.156434, -0.987689), (-0.305213, -0.156434, -0.939348), (-0.580549, -0.156434, -0.799057), (-0.799057, -0.156434, -0.580549), (-0.939348, -0.156434, -0.305213), (-0.987689, -0.156434, 0), (-0.939348, -0.156434, 0.305213), (-0.799057, -0.156434, 0.580549), (-0.580549, -0.156434, 0.799057), (-0.305213, -0.156434, 0.939348), (-2.94354e-08, -0.156434, 0.987688), (0.305212, -0.156434, 0.939348), (0.580549, -0.156434, 0.799057), (0.799057, -0.156434, 0.580549), (0.939348, -0.156434, 0.305212), (0.987688, -0.156434, 0), (0.951057, 0, -0.309017), (0.809018, 0, -0.587786), (0.587786, 0, -0.809017), (0.309017, 0, -0.951057), (0, 0, -1), (-0.309017, 0, -0.951057), (-0.587785, 0, -0.809017), (-0.809017, 0, -0.587785), (-0.951057, 0, -0.309017), (-1, 0, 0), (-0.951057, 0, 0.309017), (-0.809017, 0, 0.587785), (-0.587785, 0, 0.809017), (-0.309017, 0, 0.951057), (-2.98023e-08, 0, 1), (0.309017, 0, 0.951057), (0.587785, 0, 0.809017), (0.809017, 0, 0.587785), (0.951057, 0, 0.309017), (1, 0, 0), (0.939348, 0.156434, -0.305213), (0.799057, 0.156434, -0.580549), (0.580549, 0.156434, -0.799057), (0.305213, 0.156434, -0.939348), (0, 0.156434, -0.987689), (-0.305213, 0.156434, -0.939348), (-0.580549, 0.156434, -0.799057), (-0.799057, 0.156434, -0.580549), (-0.939348, 0.156434, -0.305213), (-0.987689, 0.156434, 0), (-0.939348, 0.156434, 0.305213), (-0.799057, 0.156434, 0.580549), (-0.580549, 0.156434, 0.799057), (-0.305213, 0.156434, 0.939348), (-2.94354e-08, 0.156434, 0.987688), (0.305212, 0.156434, 0.939348), (0.580549, 0.156434, 0.799057), (0.799057, 0.156434, 0.580549), (0.939348, 0.156434, 0.305212), (0.987688, 0.156434, 0), (0.904509, 0.309017, -0.293893), (0.769421, 0.309017, -0.559017), (0.559017, 0.309017, -0.769421), (0.293893, 0.309017, -0.904509), (0, 0.309017, -0.951057), (-0.293893, 0.309017, -0.904509), (-0.559017, 0.309017, -0.769421), (-0.769421, 0.309017, -0.559017), (-0.904509, 0.309017, -0.293893), (-0.951057, 0.309017, 0), (-0.904509, 0.309017, 0.293893), (-0.769421, 0.309017, 0.559017), (-0.559017, 0.309017, 0.769421), (-0.293893, 0.309017, 0.904509), (-2.83437e-08, 0.309017, 0.951057), (0.293893, 0.309017, 0.904509), (0.559017, 0.309017, 0.769421), (0.769421, 0.309017, 0.559017), (0.904509, 0.309017, 0.293893), (0.951057, 0.309017, 0), (0.847398, 0.453991, -0.275336), (0.72084, 0.453991, -0.523721), (0.523721, 0.453991, -0.72084), (0.275336, 0.453991, -0.847398), (0, 0.453991, -0.891007), (-0.275336, 0.453991, -0.847398), (-0.523721, 0.453991, -0.72084), (-0.72084, 0.453991, -0.523721), (-0.847398, 0.453991, -0.275336), (-0.891007, 0.453991, 0), (-0.847398, 0.453991, 0.275336), (-0.72084, 0.453991, 0.523721), (-0.523721, 0.453991, 0.72084), (-0.275336, 0.453991, 0.847398), (-2.65541e-08, 0.453991, 0.891007), (0.275336, 0.453991, 0.847398), (0.523721, 0.453991, 0.72084), (0.720839, 0.453991, 0.523721), (0.847398, 0.453991, 0.275336), (0.891007, 0.453991, 0), (0.769421, 0.587785, -0.25), (0.654509, 0.587785, -0.475529), (0.475529, 0.587785, -0.654509), (0.25, 0.587785, -0.769421), (0, 0.587785, -0.809017), (-0.25, 0.587785, -0.769421), (-0.475528, 0.587785, -0.654509), (-0.654509, 0.587785, -0.475528), (-0.769421, 0.587785, -0.25), (-0.809017, 0.587785, 0), (-0.769421, 0.587785, 0.25), (-0.654509, 0.587785, 0.475528), (-0.475528, 0.587785, 0.654509), (-0.25, 0.587785, 0.769421), (-2.41106e-08, 0.587785, 0.809017), (0.25, 0.587785, 0.769421), (0.475528, 0.587785, 0.654509), (0.654509, 0.587785, 0.475528), (0.769421, 0.587785, 0.25), (0.809017, 0.587785, 0), (0.672499, 0.707107, -0.218508), (0.572062, 0.707107, -0.415627), (0.415627, 0.707107, -0.572062), (0.218508, 0.707107, -0.672499), (0, 0.707107, -0.707107), (-0.218508, 0.707107, -0.672499), (-0.415627, 0.707107, -0.572062), (-0.572062, 0.707107, -0.415627), (-0.672499, 0.707107, -0.218508), (-0.707107, 0.707107, 0), (-0.672499, 0.707107, 0.218508), (-0.572062, 0.707107, 0.415627), (-0.415627, 0.707107, 0.572061), (-0.218508, 0.707107, 0.672499), (-2.10734e-08, 0.707107, 0.707107), (0.218508, 0.707107, 0.672499), (0.415627, 0.707107, 0.572061), (0.572061, 0.707107, 0.415627), (0.672499, 0.707107, 0.218508), (0.707107, 0.707107, 0), (0.559017, 0.809017, -0.181636), (0.475529, 0.809017, -0.345492), (0.345492, 0.809017, -0.475529), (0.181636, 0.809017, -0.559017), (0, 0.809017, -0.587786), (-0.181636, 0.809017, -0.559017), (-0.345492, 0.809017, -0.475528), (-0.475528, 0.809017, -0.345492), (-0.559017, 0.809017, -0.181636), (-0.587785, 0.809017, 0), (-0.559017, 0.809017, 0.181636), (-0.475528, 0.809017, 0.345492), (-0.345492, 0.809017, 0.475528), (-0.181636, 0.809017, 0.559017), (-1.75174e-08, 0.809017, 0.587785), (0.181636, 0.809017, 0.559017), (0.345491, 0.809017, 0.475528), (0.475528, 0.809017, 0.345492), (0.559017, 0.809017, 0.181636), (0.587785, 0.809017, 0), (0.431771, 0.891007, -0.140291), (0.367286, 0.891007, -0.266849), (0.266849, 0.891007, -0.367286), (0.140291, 0.891007, -0.431771), (0, 0.891007, -0.453991), (-0.140291, 0.891007, -0.431771), (-0.266849, 0.891007, -0.367286), (-0.367286, 0.891007, -0.266849), (-0.431771, 0.891007, -0.140291), (-0.453991, 0.891007, 0), (-0.431771, 0.891007, 0.140291), (-0.367286, 0.891007, 0.266849), (-0.266849, 0.891007, 0.367286), (-0.140291, 0.891007, 0.431771), (-1.353e-08, 0.891007, 0.453991), (0.140291, 0.891007, 0.431771), (0.266849, 0.891007, 0.367286), (0.367286, 0.891007, 0.266849), (0.431771, 0.891007, 0.140291), (0.453991, 0.891007, 0), (0.293893, 0.951057, -0.0954916), (0.25, 0.951057, -0.181636), (0.181636, 0.951057, -0.25), (0.0954916, 0.951057, -0.293893), (0, 0.951057, -0.309017), (-0.0954916, 0.951057, -0.293893), (-0.181636, 0.951057, -0.25), (-0.25, 0.951057, -0.181636), (-0.293893, 0.951057, -0.0954915), (-0.309017, 0.951057, 0), (-0.293893, 0.951057, 0.0954915), (-0.25, 0.951057, 0.181636), (-0.181636, 0.951057, 0.25), (-0.0954915, 0.951057, 0.293893), (-9.20942e-09, 0.951057, 0.309017), (0.0954915, 0.951057, 0.293893), (0.181636, 0.951057, 0.25), (0.25, 0.951057, 0.181636), (0.293893, 0.951057, 0.0954915), (0.309017, 0.951057, 0), (0.148778, 0.987688, -0.0483409), (0.126558, 0.987688, -0.0919499), (0.0919499, 0.987688, -0.126558), (0.0483409, 0.987688, -0.148778), (0, 0.987688, -0.156435), (-0.0483409, 0.987688, -0.148778), (-0.0919499, 0.987688, -0.126558), (-0.126558, 0.987688, -0.0919499), (-0.148778, 0.987688, -0.0483409), (-0.156435, 0.987688, 0), (-0.148778, 0.987688, 0.0483409), (-0.126558, 0.987688, 0.0919499), (-0.0919499, 0.987688, 0.126558), (-0.0483409, 0.987688, 0.148778), (-4.66211e-09, 0.987688, 0.156434), (0.0483409, 0.987688, 0.148778), (0.0919499, 0.987688, 0.126558), (0.126558, 0.987688, 0.0919499), (0.148778, 0.987688, 0.0483409), (0.156434, 0.987688, 0), (0, -1, 0), (0, 1, 0)] + string primvars:__handleid = "${user:ModelInstance}_pSphere1" ( + interpolation = "constant" + ) + color3f[] primvars:displayColor = [(0.217638, 0.217638, 0.217638)] + float3[] primvars:ModelBuildRefPose = [(0.148778, -0.987688, -0.0483409), (0.126558, -0.987688, -0.0919499), (0.0919499, -0.987688, -0.126558), (0.0483409, -0.987688, -0.148778), (0, -0.987688, -0.156435), (-0.0483409, -0.987688, -0.148778), (-0.0919499, -0.987688, -0.126558), (-0.126558, -0.987688, -0.0919499), (-0.148778, -0.987688, -0.0483409), (-0.156435, -0.987688, 0), (-0.148778, -0.987688, 0.0483409), (-0.126558, -0.987688, 0.0919499), (-0.0919499, -0.987688, 0.126558), (-0.0483409, -0.987688, 0.148778), (-4.66211e-09, -0.987688, 0.156434), (0.0483409, -0.987688, 0.148778), (0.0919499, -0.987688, 0.126558), (0.126558, -0.987688, 0.0919499), (0.148778, -0.987688, 0.0483409), (0.156434, -0.987688, 0), (0.293893, -0.951057, -0.0954916), (0.25, -0.951057, -0.181636), (0.181636, -0.951057, -0.25), (0.0954916, -0.951057, -0.293893), (0, -0.951057, -0.309017), (-0.0954916, -0.951057, -0.293893), (-0.181636, -0.951057, -0.25), (-0.25, -0.951057, -0.181636), (-0.293893, -0.951057, -0.0954915), (-0.309017, -0.951057, 0), (-0.293893, -0.951057, 0.0954915), (-0.25, -0.951057, 0.181636), (-0.181636, -0.951057, 0.25), (-0.0954915, -0.951057, 0.293893), (-9.20942e-09, -0.951057, 0.309017), (0.0954915, -0.951057, 0.293893), (0.181636, -0.951057, 0.25), (0.25, -0.951057, 0.181636), (0.293893, -0.951057, 0.0954915), (0.309017, -0.951057, 0), (0.431771, -0.891007, -0.140291), (0.367286, -0.891007, -0.266849), (0.266849, -0.891007, -0.367286), (0.140291, -0.891007, -0.431771), (0, -0.891007, -0.453991), (-0.140291, -0.891007, -0.431771), (-0.266849, -0.891007, -0.367286), (-0.367286, -0.891007, -0.266849), (-0.431771, -0.891007, -0.140291), (-0.453991, -0.891007, 0), (-0.431771, -0.891007, 0.140291), (-0.367286, -0.891007, 0.266849), (-0.266849, -0.891007, 0.367286), (-0.140291, -0.891007, 0.431771), (-1.353e-08, -0.891007, 0.453991), (0.140291, -0.891007, 0.431771), (0.266849, -0.891007, 0.367286), (0.367286, -0.891007, 0.266849), (0.431771, -0.891007, 0.140291), (0.453991, -0.891007, 0), (0.559017, -0.809017, -0.181636), (0.475529, -0.809017, -0.345492), (0.345492, -0.809017, -0.475529), (0.181636, -0.809017, -0.559017), (0, -0.809017, -0.587786), (-0.181636, -0.809017, -0.559017), (-0.345492, -0.809017, -0.475528), (-0.475528, -0.809017, -0.345492), (-0.559017, -0.809017, -0.181636), (-0.587785, -0.809017, 0), (-0.559017, -0.809017, 0.181636), (-0.475528, -0.809017, 0.345492), (-0.345492, -0.809017, 0.475528), (-0.181636, -0.809017, 0.559017), (-1.75174e-08, -0.809017, 0.587785), (0.181636, -0.809017, 0.559017), (0.345491, -0.809017, 0.475528), (0.475528, -0.809017, 0.345492), (0.559017, -0.809017, 0.181636), (0.587785, -0.809017, 0), (0.672499, -0.707107, -0.218508), (0.572062, -0.707107, -0.415627), (0.415627, -0.707107, -0.572062), (0.218508, -0.707107, -0.672499), (0, -0.707107, -0.707107), (-0.218508, -0.707107, -0.672499), (-0.415627, -0.707107, -0.572062), (-0.572062, -0.707107, -0.415627), (-0.672499, -0.707107, -0.218508), (-0.707107, -0.707107, 0), (-0.672499, -0.707107, 0.218508), (-0.572062, -0.707107, 0.415627), (-0.415627, -0.707107, 0.572061), (-0.218508, -0.707107, 0.672499), (-2.10734e-08, -0.707107, 0.707107), (0.218508, -0.707107, 0.672499), (0.415627, -0.707107, 0.572061), (0.572061, -0.707107, 0.415627), (0.672499, -0.707107, 0.218508), (0.707107, -0.707107, 0), (0.769421, -0.587785, -0.25), (0.654509, -0.587785, -0.475529), (0.475529, -0.587785, -0.654509), (0.25, -0.587785, -0.769421), (0, -0.587785, -0.809017), (-0.25, -0.587785, -0.769421), (-0.475528, -0.587785, -0.654509), (-0.654509, -0.587785, -0.475528), (-0.769421, -0.587785, -0.25), (-0.809017, -0.587785, 0), (-0.769421, -0.587785, 0.25), (-0.654509, -0.587785, 0.475528), (-0.475528, -0.587785, 0.654509), (-0.25, -0.587785, 0.769421), (-2.41106e-08, -0.587785, 0.809017), (0.25, -0.587785, 0.769421), (0.475528, -0.587785, 0.654509), (0.654509, -0.587785, 0.475528), (0.769421, -0.587785, 0.25), (0.809017, -0.587785, 0), (0.847398, -0.453991, -0.275336), (0.72084, -0.453991, -0.523721), (0.523721, -0.453991, -0.72084), (0.275336, -0.453991, -0.847398), (0, -0.453991, -0.891007), (-0.275336, -0.453991, -0.847398), (-0.523721, -0.453991, -0.72084), (-0.72084, -0.453991, -0.523721), (-0.847398, -0.453991, -0.275336), (-0.891007, -0.453991, 0), (-0.847398, -0.453991, 0.275336), (-0.72084, -0.453991, 0.523721), (-0.523721, -0.453991, 0.72084), (-0.275336, -0.453991, 0.847398), (-2.65541e-08, -0.453991, 0.891007), (0.275336, -0.453991, 0.847398), (0.523721, -0.453991, 0.72084), (0.720839, -0.453991, 0.523721), (0.847398, -0.453991, 0.275336), (0.891007, -0.453991, 0), (0.904509, -0.309017, -0.293893), (0.769421, -0.309017, -0.559017), (0.559017, -0.309017, -0.769421), (0.293893, -0.309017, -0.904509), (0, -0.309017, -0.951057), (-0.293893, -0.309017, -0.904509), (-0.559017, -0.309017, -0.769421), (-0.769421, -0.309017, -0.559017), (-0.904509, -0.309017, -0.293893), (-0.951057, -0.309017, 0), (-0.904509, -0.309017, 0.293893), (-0.769421, -0.309017, 0.559017), (-0.559017, -0.309017, 0.769421), (-0.293893, -0.309017, 0.904509), (-2.83437e-08, -0.309017, 0.951057), (0.293893, -0.309017, 0.904509), (0.559017, -0.309017, 0.769421), (0.769421, -0.309017, 0.559017), (0.904509, -0.309017, 0.293893), (0.951057, -0.309017, 0), (0.939348, -0.156434, -0.305213), (0.799057, -0.156434, -0.580549), (0.580549, -0.156434, -0.799057), (0.305213, -0.156434, -0.939348), (0, -0.156434, -0.987689), (-0.305213, -0.156434, -0.939348), (-0.580549, -0.156434, -0.799057), (-0.799057, -0.156434, -0.580549), (-0.939348, -0.156434, -0.305213), (-0.987689, -0.156434, 0), (-0.939348, -0.156434, 0.305213), (-0.799057, -0.156434, 0.580549), (-0.580549, -0.156434, 0.799057), (-0.305213, -0.156434, 0.939348), (-2.94354e-08, -0.156434, 0.987688), (0.305212, -0.156434, 0.939348), (0.580549, -0.156434, 0.799057), (0.799057, -0.156434, 0.580549), (0.939348, -0.156434, 0.305212), (0.987688, -0.156434, 0), (0.951057, 0, -0.309017), (0.809018, 0, -0.587786), (0.587786, 0, -0.809017), (0.309017, 0, -0.951057), (0, 0, -1), (-0.309017, 0, -0.951057), (-0.587785, 0, -0.809017), (-0.809017, 0, -0.587785), (-0.951057, 0, -0.309017), (-1, 0, 0), (-0.951057, 0, 0.309017), (-0.809017, 0, 0.587785), (-0.587785, 0, 0.809017), (-0.309017, 0, 0.951057), (-2.98023e-08, 0, 1), (0.309017, 0, 0.951057), (0.587785, 0, 0.809017), (0.809017, 0, 0.587785), (0.951057, 0, 0.309017), (1, 0, 0), (0.939348, 0.156434, -0.305213), (0.799057, 0.156434, -0.580549), (0.580549, 0.156434, -0.799057), (0.305213, 0.156434, -0.939348), (0, 0.156434, -0.987689), (-0.305213, 0.156434, -0.939348), (-0.580549, 0.156434, -0.799057), (-0.799057, 0.156434, -0.580549), (-0.939348, 0.156434, -0.305213), (-0.987689, 0.156434, 0), (-0.939348, 0.156434, 0.305213), (-0.799057, 0.156434, 0.580549), (-0.580549, 0.156434, 0.799057), (-0.305213, 0.156434, 0.939348), (-2.94354e-08, 0.156434, 0.987688), (0.305212, 0.156434, 0.939348), (0.580549, 0.156434, 0.799057), (0.799057, 0.156434, 0.580549), (0.939348, 0.156434, 0.305212), (0.987688, 0.156434, 0), (0.904509, 0.309017, -0.293893), (0.769421, 0.309017, -0.559017), (0.559017, 0.309017, -0.769421), (0.293893, 0.309017, -0.904509), (0, 0.309017, -0.951057), (-0.293893, 0.309017, -0.904509), (-0.559017, 0.309017, -0.769421), (-0.769421, 0.309017, -0.559017), (-0.904509, 0.309017, -0.293893), (-0.951057, 0.309017, 0), (-0.904509, 0.309017, 0.293893), (-0.769421, 0.309017, 0.559017), (-0.559017, 0.309017, 0.769421), (-0.293893, 0.309017, 0.904509), (-2.83437e-08, 0.309017, 0.951057), (0.293893, 0.309017, 0.904509), (0.559017, 0.309017, 0.769421), (0.769421, 0.309017, 0.559017), (0.904509, 0.309017, 0.293893), (0.951057, 0.309017, 0), (0.847398, 0.453991, -0.275336), (0.72084, 0.453991, -0.523721), (0.523721, 0.453991, -0.72084), (0.275336, 0.453991, -0.847398), (0, 0.453991, -0.891007), (-0.275336, 0.453991, -0.847398), (-0.523721, 0.453991, -0.72084), (-0.72084, 0.453991, -0.523721), (-0.847398, 0.453991, -0.275336), (-0.891007, 0.453991, 0), (-0.847398, 0.453991, 0.275336), (-0.72084, 0.453991, 0.523721), (-0.523721, 0.453991, 0.72084), (-0.275336, 0.453991, 0.847398), (-2.65541e-08, 0.453991, 0.891007), (0.275336, 0.453991, 0.847398), (0.523721, 0.453991, 0.72084), (0.720839, 0.453991, 0.523721), (0.847398, 0.453991, 0.275336), (0.891007, 0.453991, 0), (0.769421, 0.587785, -0.25), (0.654509, 0.587785, -0.475529), (0.475529, 0.587785, -0.654509), (0.25, 0.587785, -0.769421), (0, 0.587785, -0.809017), (-0.25, 0.587785, -0.769421), (-0.475528, 0.587785, -0.654509), (-0.654509, 0.587785, -0.475528), (-0.769421, 0.587785, -0.25), (-0.809017, 0.587785, 0), (-0.769421, 0.587785, 0.25), (-0.654509, 0.587785, 0.475528), (-0.475528, 0.587785, 0.654509), (-0.25, 0.587785, 0.769421), (-2.41106e-08, 0.587785, 0.809017), (0.25, 0.587785, 0.769421), (0.475528, 0.587785, 0.654509), (0.654509, 0.587785, 0.475528), (0.769421, 0.587785, 0.25), (0.809017, 0.587785, 0), (0.672499, 0.707107, -0.218508), (0.572062, 0.707107, -0.415627), (0.415627, 0.707107, -0.572062), (0.218508, 0.707107, -0.672499), (0, 0.707107, -0.707107), (-0.218508, 0.707107, -0.672499), (-0.415627, 0.707107, -0.572062), (-0.572062, 0.707107, -0.415627), (-0.672499, 0.707107, -0.218508), (-0.707107, 0.707107, 0), (-0.672499, 0.707107, 0.218508), (-0.572062, 0.707107, 0.415627), (-0.415627, 0.707107, 0.572061), (-0.218508, 0.707107, 0.672499), (-2.10734e-08, 0.707107, 0.707107), (0.218508, 0.707107, 0.672499), (0.415627, 0.707107, 0.572061), (0.572061, 0.707107, 0.415627), (0.672499, 0.707107, 0.218508), (0.707107, 0.707107, 0), (0.559017, 0.809017, -0.181636), (0.475529, 0.809017, -0.345492), (0.345492, 0.809017, -0.475529), (0.181636, 0.809017, -0.559017), (0, 0.809017, -0.587786), (-0.181636, 0.809017, -0.559017), (-0.345492, 0.809017, -0.475528), (-0.475528, 0.809017, -0.345492), (-0.559017, 0.809017, -0.181636), (-0.587785, 0.809017, 0), (-0.559017, 0.809017, 0.181636), (-0.475528, 0.809017, 0.345492), (-0.345492, 0.809017, 0.475528), (-0.181636, 0.809017, 0.559017), (-1.75174e-08, 0.809017, 0.587785), (0.181636, 0.809017, 0.559017), (0.345491, 0.809017, 0.475528), (0.475528, 0.809017, 0.345492), (0.559017, 0.809017, 0.181636), (0.587785, 0.809017, 0), (0.431771, 0.891007, -0.140291), (0.367286, 0.891007, -0.266849), (0.266849, 0.891007, -0.367286), (0.140291, 0.891007, -0.431771), (0, 0.891007, -0.453991), (-0.140291, 0.891007, -0.431771), (-0.266849, 0.891007, -0.367286), (-0.367286, 0.891007, -0.266849), (-0.431771, 0.891007, -0.140291), (-0.453991, 0.891007, 0), (-0.431771, 0.891007, 0.140291), (-0.367286, 0.891007, 0.266849), (-0.266849, 0.891007, 0.367286), (-0.140291, 0.891007, 0.431771), (-1.353e-08, 0.891007, 0.453991), (0.140291, 0.891007, 0.431771), (0.266849, 0.891007, 0.367286), (0.367286, 0.891007, 0.266849), (0.431771, 0.891007, 0.140291), (0.453991, 0.891007, 0), (0.293893, 0.951057, -0.0954916), (0.25, 0.951057, -0.181636), (0.181636, 0.951057, -0.25), (0.0954916, 0.951057, -0.293893), (0, 0.951057, -0.309017), (-0.0954916, 0.951057, -0.293893), (-0.181636, 0.951057, -0.25), (-0.25, 0.951057, -0.181636), (-0.293893, 0.951057, -0.0954915), (-0.309017, 0.951057, 0), (-0.293893, 0.951057, 0.0954915), (-0.25, 0.951057, 0.181636), (-0.181636, 0.951057, 0.25), (-0.0954915, 0.951057, 0.293893), (-9.20942e-09, 0.951057, 0.309017), (0.0954915, 0.951057, 0.293893), (0.181636, 0.951057, 0.25), (0.25, 0.951057, 0.181636), (0.293893, 0.951057, 0.0954915), (0.309017, 0.951057, 0), (0.148778, 0.987688, -0.0483409), (0.126558, 0.987688, -0.0919499), (0.0919499, 0.987688, -0.126558), (0.0483409, 0.987688, -0.148778), (0, 0.987688, -0.156435), (-0.0483409, 0.987688, -0.148778), (-0.0919499, 0.987688, -0.126558), (-0.126558, 0.987688, -0.0919499), (-0.148778, 0.987688, -0.0483409), (-0.156435, 0.987688, 0), (-0.148778, 0.987688, 0.0483409), (-0.126558, 0.987688, 0.0919499), (-0.0919499, 0.987688, 0.126558), (-0.0483409, 0.987688, 0.148778), (-4.66211e-09, 0.987688, 0.156434), (0.0483409, 0.987688, 0.148778), (0.0919499, 0.987688, 0.126558), (0.126558, 0.987688, 0.0919499), (0.148778, 0.987688, 0.0483409), (0.156434, 0.987688, 0), (0, -1, 0), (0, 1, 0)] ( + interpolation = "vertex" + ) + float[] primvars:ptexFaceIndex = [0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63, 64, 64, 64, 64, 65, 65, 65, 65, 66, 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 69, 69, 69, 70, 70, 70, 70, 71, 71, 71, 71, 72, 72, 72, 72, 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, 77, 78, 78, 78, 78, 79, 79, 79, 79, 80, 80, 80, 80, 81, 81, 81, 81, 82, 82, 82, 82, 83, 83, 83, 83, 84, 84, 84, 84, 85, 85, 85, 85, 86, 86, 86, 86, 87, 87, 87, 87, 88, 88, 88, 88, 89, 89, 89, 89, 90, 90, 90, 90, 91, 91, 91, 91, 92, 92, 92, 92, 93, 93, 93, 93, 94, 94, 94, 94, 95, 95, 95, 95, 96, 96, 96, 96, 97, 97, 97, 97, 98, 98, 98, 98, 99, 99, 99, 99, 100, 100, 100, 100, 101, 101, 101, 101, 102, 102, 102, 102, 103, 103, 103, 103, 104, 104, 104, 104, 105, 105, 105, 105, 106, 106, 106, 106, 107, 107, 107, 107, 108, 108, 108, 108, 109, 109, 109, 109, 110, 110, 110, 110, 111, 111, 111, 111, 112, 112, 112, 112, 113, 113, 113, 113, 114, 114, 114, 114, 115, 115, 115, 115, 116, 116, 116, 116, 117, 117, 117, 117, 118, 118, 118, 118, 119, 119, 119, 119, 120, 120, 120, 120, 121, 121, 121, 121, 122, 122, 122, 122, 123, 123, 123, 123, 124, 124, 124, 124, 125, 125, 125, 125, 126, 126, 126, 126, 127, 127, 127, 127, 128, 128, 128, 128, 129, 129, 129, 129, 130, 130, 130, 130, 131, 131, 131, 131, 132, 132, 132, 132, 133, 133, 133, 133, 134, 134, 134, 134, 135, 135, 135, 135, 136, 136, 136, 136, 137, 137, 137, 137, 138, 138, 138, 138, 139, 139, 139, 139, 140, 140, 140, 140, 141, 141, 141, 141, 142, 142, 142, 142, 143, 143, 143, 143, 144, 144, 144, 144, 145, 145, 145, 145, 146, 146, 146, 146, 147, 147, 147, 147, 148, 148, 148, 148, 149, 149, 149, 149, 150, 150, 150, 150, 151, 151, 151, 151, 152, 152, 152, 152, 153, 153, 153, 153, 154, 154, 154, 154, 155, 155, 155, 155, 156, 156, 156, 156, 157, 157, 157, 157, 158, 158, 158, 158, 159, 159, 159, 159, 160, 160, 160, 160, 161, 161, 161, 161, 162, 162, 162, 162, 163, 163, 163, 163, 164, 164, 164, 164, 165, 165, 165, 165, 166, 166, 166, 166, 167, 167, 167, 167, 168, 168, 168, 168, 169, 169, 169, 169, 170, 170, 170, 170, 171, 171, 171, 171, 172, 172, 172, 172, 173, 173, 173, 173, 174, 174, 174, 174, 175, 175, 175, 175, 176, 176, 176, 176, 177, 177, 177, 177, 178, 178, 178, 178, 179, 179, 179, 179, 180, 180, 180, 180, 181, 181, 181, 181, 182, 182, 182, 182, 183, 183, 183, 183, 184, 184, 184, 184, 185, 185, 185, 185, 186, 186, 186, 186, 187, 187, 187, 187, 188, 188, 188, 188, 189, 189, 189, 189, 190, 190, 190, 190, 191, 191, 191, 191, 192, 192, 192, 192, 193, 193, 193, 193, 194, 194, 194, 194, 195, 195, 195, 195, 196, 196, 196, 196, 197, 197, 197, 197, 198, 198, 198, 198, 199, 199, 199, 199, 200, 200, 200, 200, 201, 201, 201, 201, 202, 202, 202, 202, 203, 203, 203, 203, 204, 204, 204, 204, 205, 205, 205, 205, 206, 206, 206, 206, 207, 207, 207, 207, 208, 208, 208, 208, 209, 209, 209, 209, 210, 210, 210, 210, 211, 211, 211, 211, 212, 212, 212, 212, 213, 213, 213, 213, 214, 214, 214, 214, 215, 215, 215, 215, 216, 216, 216, 216, 217, 217, 217, 217, 218, 218, 218, 218, 219, 219, 219, 219, 220, 220, 220, 220, 221, 221, 221, 221, 222, 222, 222, 222, 223, 223, 223, 223, 224, 224, 224, 224, 225, 225, 225, 225, 226, 226, 226, 226, 227, 227, 227, 227, 228, 228, 228, 228, 229, 229, 229, 229, 230, 230, 230, 230, 231, 231, 231, 231, 232, 232, 232, 232, 233, 233, 233, 233, 234, 234, 234, 234, 235, 235, 235, 235, 236, 236, 236, 236, 237, 237, 237, 237, 238, 238, 238, 238, 239, 239, 239, 239, 240, 240, 240, 240, 241, 241, 241, 241, 242, 242, 242, 242, 243, 243, 243, 243, 244, 244, 244, 244, 245, 245, 245, 245, 246, 246, 246, 246, 247, 247, 247, 247, 248, 248, 248, 248, 249, 249, 249, 249, 250, 250, 250, 250, 251, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254, 254, 254, 254, 255, 255, 255, 255, 256, 256, 256, 256, 257, 257, 257, 257, 258, 258, 258, 258, 259, 259, 259, 259, 260, 260, 260, 260, 261, 261, 261, 261, 262, 262, 262, 262, 263, 263, 263, 263, 264, 264, 264, 264, 265, 265, 265, 265, 266, 266, 266, 266, 267, 267, 267, 267, 268, 268, 268, 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, 272, 272, 273, 273, 273, 273, 274, 274, 274, 274, 275, 275, 275, 275, 276, 276, 276, 276, 277, 277, 277, 277, 278, 278, 278, 278, 279, 279, 279, 279, 280, 280, 280, 280, 281, 281, 281, 281, 282, 282, 282, 282, 283, 283, 283, 283, 284, 284, 284, 284, 285, 285, 285, 285, 286, 286, 286, 286, 287, 287, 287, 287, 288, 288, 288, 288, 289, 289, 289, 289, 290, 290, 290, 290, 291, 291, 291, 291, 292, 292, 292, 292, 293, 293, 293, 293, 294, 294, 294, 294, 295, 295, 295, 295, 296, 296, 296, 296, 297, 297, 297, 297, 298, 298, 298, 298, 299, 299, 299, 299, 300, 300, 300, 300, 301, 301, 301, 301, 302, 302, 302, 302, 303, 303, 303, 303, 304, 304, 304, 304, 305, 305, 305, 305, 306, 306, 306, 306, 307, 307, 307, 307, 308, 308, 308, 308, 309, 309, 309, 309, 310, 310, 310, 310, 311, 311, 311, 311, 312, 312, 312, 312, 313, 313, 313, 313, 314, 314, 314, 314, 315, 315, 315, 315, 316, 316, 316, 316, 317, 317, 317, 317, 318, 318, 318, 318, 319, 319, 319, 319, 320, 320, 320, 320, 321, 321, 321, 321, 322, 322, 322, 322, 323, 323, 323, 323, 324, 324, 324, 324, 325, 325, 325, 325, 326, 326, 326, 326, 327, 327, 327, 327, 328, 328, 328, 328, 329, 329, 329, 329, 330, 330, 330, 330, 331, 331, 331, 331, 332, 332, 332, 332, 333, 333, 333, 333, 334, 334, 334, 334, 335, 335, 335, 335, 336, 336, 336, 336, 337, 337, 337, 337, 338, 338, 338, 338, 339, 339, 339, 339, 340, 340, 340, 340, 341, 341, 341, 341, 342, 342, 342, 342, 343, 343, 343, 343, 344, 344, 344, 344, 345, 345, 345, 345, 346, 346, 346, 346, 347, 347, 347, 347, 348, 348, 348, 348, 349, 349, 349, 349, 350, 350, 350, 350, 351, 351, 351, 351, 352, 352, 352, 352, 353, 353, 353, 353, 354, 354, 354, 354, 355, 355, 355, 355, 356, 356, 356, 356, 357, 357, 357, 357, 358, 358, 358, 358, 359, 359, 359, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479] ( + interpolation = "faceVarying" + ) + int primvars:ptexFaceOffset = 0 ( + interpolation = "constant" + ) + float[] primvars:u_map1 = [0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0.05, 0, 0.025, 0.1, 0.05, 0.075, 0.15, 0.1, 0.125, 0.2, 0.15, 0.175, 0.25, 0.2, 0.22500001, 0.3, 0.25, 0.275, 0.35000002, 0.3, 0.32500002, 0.40000004, 0.35000002, 0.375, 0.45000005, 0.40000004, 0.425, 0.50000006, 0.45000005, 0.475, 0.5500001, 0.50000006, 0.52500004, 0.6000001, 0.5500001, 0.575, 0.6500001, 0.6000001, 0.625, 0.7000001, 0.6500001, 0.675, 0.7500001, 0.7000001, 0.725, 0.80000013, 0.7500001, 0.77500004, 0.85000014, 0.80000013, 0.825, 0.90000015, 0.85000014, 0.875, 0.95000017, 0.90000015, 0.925, 1.0000001, 0.95000017, 0.975, 0, 0.05, 0.025, 0.05, 0.1, 0.075, 0.1, 0.15, 0.125, 0.15, 0.2, 0.175, 0.2, 0.25, 0.22500001, 0.25, 0.3, 0.275, 0.3, 0.35000002, 0.32500002, 0.35000002, 0.40000004, 0.375, 0.40000004, 0.45000005, 0.425, 0.45000005, 0.50000006, 0.475, 0.50000006, 0.5500001, 0.52500004, 0.5500001, 0.6000001, 0.575, 0.6000001, 0.6500001, 0.625, 0.6500001, 0.7000001, 0.675, 0.7000001, 0.7500001, 0.725, 0.7500001, 0.80000013, 0.77500004, 0.80000013, 0.85000014, 0.825, 0.85000014, 0.90000015, 0.875, 0.90000015, 0.95000017, 0.925, 0.95000017, 1.0000001, 0.975] ( + interpolation = "faceVarying" + ) + float[] primvars:v_map1 = [0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0, 1] ( + interpolation = "vertex" + ) + } + + def Mesh "pCube1" ( + hidden = true + ) + { + float3[] extent = [(-0.5, -0.5, -0.5), (0.5, 0.5, 0.5)] + int[] faceVertexCounts = [4, 4, 4, 4, 4, 4] + int[] faceVertexIndices = [0, 1, 3, 2, 2, 3, 5, 4, 4, 5, 7, 6, 6, 7, 1, 0, 1, 7, 5, 3, 6, 0, 2, 4] + token interpolateBoundary = "edgeAndCorner" + uniform token orientation = "rightHanded" + float3[] points = [(-0.5, -0.5, 0.5), (0.5, -0.5, 0.5), (-0.5, 0.5, 0.5), (0.5, 0.5, 0.5), (-0.5, 0.5, -0.5), (0.5, 0.5, -0.5), (-0.5, -0.5, -0.5), (0.5, -0.5, -0.5)] + string primvars:__handleid = "${user:ModelInstance}_pCube1" ( + interpolation = "constant" + ) + color3f[] primvars:displayColor = [(0.217638, 0.217638, 0.217638)] + float3[] primvars:ModelBuildRefPose = [(-0.5, -0.5, 0.5), (0.5, -0.5, 0.5), (-0.5, 0.5, 0.5), (0.5, 0.5, 0.5), (-0.5, 0.5, -0.5), (0.5, 0.5, -0.5), (-0.5, -0.5, -0.5), (0.5, -0.5, -0.5)] ( + interpolation = "vertex" + ) + float[] primvars:ptexFaceIndex = [0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5] ( + interpolation = "faceVarying" + ) + int primvars:ptexFaceOffset = 480 ( + interpolation = "constant" + ) + float[] primvars:u_map1 = [0.375, 0.625, 0.625, 0.375, 0.375, 0.625, 0.625, 0.375, 0.375, 0.625, 0.625, 0.375, 0.375, 0.625, 0.625, 0.375, 0.625, 0.875, 0.875, 0.625, 0.125, 0.375, 0.375, 0.125] ( + interpolation = "faceVarying" + ) + float[] primvars:v_map1 = [0, 0, 0.25, 0.25, 0.25, 0.25, 0.5, 0.5, 0.5, 0.5, 0.75, 0.75, 0.75, 0.75, 1, 1, 0, 0, 0.25, 0.25, 0, 0, 0.25, 0.25] ( + interpolation = "faceVarying" + ) + } + + def Mesh "pCylinder1" ( + hidden = true + ) + { + float3[] extent = [(-1, -1, -1), (1, 1, 1)] + int[] faceVertexCounts = [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3] + int[] faceVertexIndices = [0, 1, 21, 20, 1, 2, 22, 21, 2, 3, 23, 22, 3, 4, 24, 23, 4, 5, 25, 24, 5, 6, 26, 25, 6, 7, 27, 26, 7, 8, 28, 27, 8, 9, 29, 28, 9, 10, 30, 29, 10, 11, 31, 30, 11, 12, 32, 31, 12, 13, 33, 32, 13, 14, 34, 33, 14, 15, 35, 34, 15, 16, 36, 35, 16, 17, 37, 36, 17, 18, 38, 37, 18, 19, 39, 38, 19, 0, 20, 39, 1, 0, 40, 2, 1, 40, 3, 2, 40, 4, 3, 40, 5, 4, 40, 6, 5, 40, 7, 6, 40, 8, 7, 40, 9, 8, 40, 10, 9, 40, 11, 10, 40, 12, 11, 40, 13, 12, 40, 14, 13, 40, 15, 14, 40, 16, 15, 40, 17, 16, 40, 18, 17, 40, 19, 18, 40, 0, 19, 40, 20, 21, 41, 21, 22, 41, 22, 23, 41, 23, 24, 41, 24, 25, 41, 25, 26, 41, 26, 27, 41, 27, 28, 41, 28, 29, 41, 29, 30, 41, 30, 31, 41, 31, 32, 41, 32, 33, 41, 33, 34, 41, 34, 35, 41, 35, 36, 41, 36, 37, 41, 37, 38, 41, 38, 39, 41, 39, 20, 41] + token interpolateBoundary = "edgeAndCorner" + uniform token orientation = "rightHanded" + float3[] points = [(0.951057, -1, -0.309017), (0.809018, -1, -0.587786), (0.587786, -1, -0.809017), (0.309017, -1, -0.951057), (0, -1, -1), (-0.309017, -1, -0.951057), (-0.587785, -1, -0.809017), (-0.809017, -1, -0.587785), (-0.951057, -1, -0.309017), (-1, -1, 0), (-0.951057, -1, 0.309017), (-0.809017, -1, 0.587785), (-0.587785, -1, 0.809017), (-0.309017, -1, 0.951057), (-2.98023e-08, -1, 1), (0.309017, -1, 0.951057), (0.587785, -1, 0.809017), (0.809017, -1, 0.587785), (0.951057, -1, 0.309017), (1, -1, 0), (0.951057, 1, -0.309017), (0.809018, 1, -0.587786), (0.587786, 1, -0.809017), (0.309017, 1, -0.951057), (0, 1, -1), (-0.309017, 1, -0.951057), (-0.587785, 1, -0.809017), (-0.809017, 1, -0.587785), (-0.951057, 1, -0.309017), (-1, 1, 0), (-0.951057, 1, 0.309017), (-0.809017, 1, 0.587785), (-0.587785, 1, 0.809017), (-0.309017, 1, 0.951057), (-2.98023e-08, 1, 1), (0.309017, 1, 0.951057), (0.587785, 1, 0.809017), (0.809017, 1, 0.587785), (0.951057, 1, 0.309017), (1, 1, 0), (0, -1, 0), (0, 1, 0)] + string primvars:__handleid = "${user:ModelInstance}_pCylinder1" ( + interpolation = "constant" + ) + color3f[] primvars:displayColor = [(0.217638, 0.217638, 0.217638)] + float3[] primvars:ModelBuildRefPose = [(0.951057, -1, -0.309017), (0.809018, -1, -0.587786), (0.587786, -1, -0.809017), (0.309017, -1, -0.951057), (0, -1, -1), (-0.309017, -1, -0.951057), (-0.587785, -1, -0.809017), (-0.809017, -1, -0.587785), (-0.951057, -1, -0.309017), (-1, -1, 0), (-0.951057, -1, 0.309017), (-0.809017, -1, 0.587785), (-0.587785, -1, 0.809017), (-0.309017, -1, 0.951057), (-2.98023e-08, -1, 1), (0.309017, -1, 0.951057), (0.587785, -1, 0.809017), (0.809017, -1, 0.587785), (0.951057, -1, 0.309017), (1, -1, 0), (0.951057, 1, -0.309017), (0.809018, 1, -0.587786), (0.587786, 1, -0.809017), (0.309017, 1, -0.951057), (0, 1, -1), (-0.309017, 1, -0.951057), (-0.587785, 1, -0.809017), (-0.809017, 1, -0.587785), (-0.951057, 1, -0.309017), (-1, 1, 0), (-0.951057, 1, 0.309017), (-0.809017, 1, 0.587785), (-0.587785, 1, 0.809017), (-0.309017, 1, 0.951057), (-2.98023e-08, 1, 1), (0.309017, 1, 0.951057), (0.587785, 1, 0.809017), (0.809017, 1, 0.587785), (0.951057, 1, 0.309017), (1, 1, 0), (0, -1, 0), (0, 1, 0)] ( + interpolation = "vertex" + ) + float[] primvars:ptexFaceIndex = [0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139] ( + interpolation = "faceVarying" + ) + int primvars:ptexFaceOffset = 486 ( + interpolation = "constant" + ) + float[] primvars:u_map1 = [0.375, 0.3875, 0.3875, 0.375, 0.3875, 0.39999998, 0.39999998, 0.3875, 0.39999998, 0.41249996, 0.41249996, 0.39999998, 0.41249996, 0.42499995, 0.42499995, 0.41249996, 0.42499995, 0.43749994, 0.43749994, 0.42499995, 0.43749994, 0.44999993, 0.44999993, 0.43749994, 0.44999993, 0.46249992, 0.46249992, 0.44999993, 0.46249992, 0.4749999, 0.4749999, 0.46249992, 0.4749999, 0.4874999, 0.4874999, 0.4749999, 0.4874999, 0.49999988, 0.49999988, 0.4874999, 0.49999988, 0.51249987, 0.51249987, 0.49999988, 0.51249987, 0.52499986, 0.52499986, 0.51249987, 0.52499986, 0.53749985, 0.53749985, 0.52499986, 0.53749985, 0.54999983, 0.54999983, 0.53749985, 0.54999983, 0.5624998, 0.5624998, 0.54999983, 0.5624998, 0.5749998, 0.5749998, 0.5624998, 0.5749998, 0.5874998, 0.5874998, 0.5749998, 0.5874998, 0.5999998, 0.5999998, 0.5874998, 0.5999998, 0.6124998, 0.6124998, 0.5999998, 0.6124998, 0.62499976, 0.62499976, 0.6124998, 0.626409, 0.64860266, 0.5, 0.5918415, 0.626409, 0.5, 0.54828393, 0.5918415, 0.5, 0.5, 0.54828393, 0.5, 0.45171607, 0.5, 0.5, 0.4081585, 0.45171607, 0.5, 0.37359107, 0.4081585, 0.5, 0.3513974, 0.37359107, 0.5, 0.34374997, 0.3513974, 0.5, 0.3513974, 0.34374997, 0.5, 0.37359107, 0.3513974, 0.5, 0.40815854, 0.37359107, 0.5, 0.4517161, 0.40815854, 0.5, 0.5, 0.4517161, 0.5, 0.5482839, 0.5, 0.5, 0.59184146, 0.5482839, 0.5, 0.62640893, 0.59184146, 0.5, 0.6486026, 0.62640893, 0.5, 0.65625, 0.6486026, 0.5, 0.64860266, 0.65625, 0.5, 0.6486026, 0.62640893, 0.5, 0.62640893, 0.59184146, 0.5, 0.59184146, 0.5482839, 0.5, 0.5482839, 0.5, 0.5, 0.5, 0.4517161, 0.5, 0.4517161, 0.40815854, 0.5, 0.40815854, 0.37359107, 0.5, 0.37359107, 0.3513974, 0.5, 0.3513974, 0.34374997, 0.5, 0.34374997, 0.3513974, 0.5, 0.3513974, 0.37359107, 0.5, 0.37359107, 0.4081585, 0.5, 0.4081585, 0.45171607, 0.5, 0.45171607, 0.5, 0.5, 0.5, 0.54828393, 0.5, 0.54828393, 0.5918415, 0.5, 0.5918415, 0.626409, 0.5, 0.626409, 0.64860266, 0.5, 0.64860266, 0.65625, 0.5, 0.65625, 0.6486026, 0.5] ( + interpolation = "faceVarying" + ) + float[] primvars:v_map1 = [0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.064408496, 0.107966065, 0.15, 0.02984102, 0.064408496, 0.15, 0.0076473355, 0.02984102, 0.15, -7.4505806e-8, 0.0076473355, 0.15, 0.0076473504, -7.4505806e-8, 0.15, 0.02984105, 0.0076473504, 0.15, 0.064408526, 0.02984105, 0.15, 0.10796608, 0.064408526, 0.15, 0.15625, 0.10796608, 0.15, 0.20453392, 0.15625, 0.15, 0.24809146, 0.20453392, 0.15, 0.28265893, 0.24809146, 0.15, 0.3048526, 0.28265893, 0.15, 0.3125, 0.3048526, 0.15, 0.3048526, 0.3125, 0.15, 0.28265893, 0.3048526, 0.15, 0.24809146, 0.28265893, 0.15, 0.2045339, 0.24809146, 0.15, 0.15625, 0.2045339, 0.15, 0.107966065, 0.15625, 0.15, 0.89203393, 0.93559146, 0.8375, 0.93559146, 0.97015893, 0.8375, 0.97015893, 0.9923526, 0.8375, 0.9923526, 1, 0.8375, 1, 0.9923526, 0.8375, 0.9923526, 0.97015893, 0.8375, 0.97015893, 0.93559146, 0.8375, 0.93559146, 0.89203393, 0.8375, 0.89203393, 0.84375, 0.8375, 0.84375, 0.79546607, 0.8375, 0.79546607, 0.75190854, 0.8375, 0.75190854, 0.71734107, 0.8375, 0.71734107, 0.69514734, 0.8375, 0.69514734, 0.68749994, 0.8375, 0.68749994, 0.69514734, 0.8375, 0.69514734, 0.717341, 0.8375, 0.717341, 0.7519085, 0.8375, 0.7519085, 0.79546607, 0.8375, 0.79546607, 0.84375, 0.8375, 0.84375, 0.89203393, 0.8375] ( + interpolation = "faceVarying" + ) + } + + def Mesh "pCone1" ( + hidden = true + ) + { + float3[] extent = [(-1, -1, -1), (1, 1, 1)] + int[] faceVertexCounts = [20, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3] + int[] faceVertexIndices = [0, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 1, 20, 1, 2, 20, 2, 3, 20, 3, 4, 20, 4, 5, 20, 5, 6, 20, 6, 7, 20, 7, 8, 20, 8, 9, 20, 9, 10, 20, 10, 11, 20, 11, 12, 20, 12, 13, 20, 13, 14, 20, 14, 15, 20, 15, 16, 20, 16, 17, 20, 17, 18, 20, 18, 19, 20, 19, 0, 20] + token interpolateBoundary = "edgeAndCorner" + uniform token orientation = "rightHanded" + float3[] points = [(0.951057, -1, -0.309017), (0.809018, -1, -0.587786), (0.587786, -1, -0.809017), (0.309017, -1, -0.951057), (0, -1, -1), (-0.309017, -1, -0.951057), (-0.587785, -1, -0.809017), (-0.809017, -1, -0.587785), (-0.951057, -1, -0.309017), (-1, -1, 0), (-0.951057, -1, 0.309017), (-0.809017, -1, 0.587785), (-0.587785, -1, 0.809017), (-0.309017, -1, 0.951057), (-2.98023e-08, -1, 1), (0.309017, -1, 0.951057), (0.587785, -1, 0.809017), (0.809017, -1, 0.587785), (0.951057, -1, 0.309017), (1, -1, 0), (0, 1, 0)] + string primvars:__handleid = "${user:ModelInstance}_pCone1" ( + interpolation = "constant" + ) + color3f[] primvars:displayColor = [(0.217638, 0.217638, 0.217638)] + float3[] primvars:ModelBuildRefPose = [(0.951057, -1, -0.309017), (0.809018, -1, -0.587786), (0.587786, -1, -0.809017), (0.309017, -1, -0.951057), (0, -1, -1), (-0.309017, -1, -0.951057), (-0.587785, -1, -0.809017), (-0.809017, -1, -0.587785), (-0.951057, -1, -0.309017), (-1, -1, 0), (-0.951057, -1, 0.309017), (-0.809017, -1, 0.587785), (-0.587785, -1, 0.809017), (-0.309017, -1, 0.951057), (-2.98023e-08, -1, 1), (0.309017, -1, 0.951057), (0.587785, -1, 0.809017), (0.809017, -1, 0.587785), (0.951057, -1, 0.309017), (1, -1, 0), (0, 1, 0)] ( + interpolation = "vertex" + ) + float[] primvars:ptexFaceIndex = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79] ( + interpolation = "faceVarying" + ) + int primvars:ptexFaceOffset = 626 ( + interpolation = "constant" + ) + float[] primvars:u_map1 = [0.7377643, 0.75, 0.7377641, 0.70225424, 0.6469463, 0.57725424, 0.5, 0.42274573, 0.35305366, 0.2977457, 0.26223582, 0.24999994, 0.26223582, 0.2977457, 0.35305363, 0.4227457, 0.5, 0.5772543, 0.64694643, 0.7022544, 0.25, 0.275, 0.5, 0.275, 0.3, 0.5, 0.3, 0.32500002, 0.5, 0.32500002, 0.35000002, 0.5, 0.35000002, 0.37500003, 0.5, 0.37500003, 0.40000004, 0.5, 0.40000004, 0.42500004, 0.5, 0.42500004, 0.45000005, 0.5, 0.45000005, 0.47500005, 0.5, 0.47500005, 0.50000006, 0.5, 0.50000006, 0.52500004, 0.5, 0.52500004, 0.55, 0.5, 0.55, 0.575, 0.5, 0.575, 0.59999996, 0.5, 0.59999996, 0.62499994, 0.5, 0.62499994, 0.6499999, 0.5, 0.6499999, 0.6749999, 0.5, 0.6749999, 0.69999987, 0.5, 0.69999987, 0.72499985, 0.5, 0.72499985, 0.7499998, 0.5] ( + interpolation = "faceVarying" + ) + float[] primvars:v_map1 = [0.1727457, 0.25, 0.32725424, 0.3969463, 0.45225427, 0.48776415, 0.5, 0.48776418, 0.4522543, 0.39694634, 0.32725427, 0.25, 0.17274573, 0.103053644, 0.047745675, 0.012235761, -1.1920929e-7, 0.012235746, 0.04774563, 0.1030536, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1] ( + interpolation = "faceVarying" + ) + } + + def Mesh "pTorus1" ( + hidden = true + ) + { + float3[] extent = [(-1.5, -0.5, -1.5), (1.5, 0.5, 1.5)] + int[] faceVertexCounts = [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4] + int[] faceVertexIndices = [1, 0, 20, 21, 2, 1, 21, 22, 3, 2, 22, 23, 4, 3, 23, 24, 5, 4, 24, 25, 6, 5, 25, 26, 7, 6, 26, 27, 8, 7, 27, 28, 9, 8, 28, 29, 10, 9, 29, 30, 11, 10, 30, 31, 12, 11, 31, 32, 13, 12, 32, 33, 14, 13, 33, 34, 15, 14, 34, 35, 16, 15, 35, 36, 17, 16, 36, 37, 18, 17, 37, 38, 19, 18, 38, 39, 0, 19, 39, 20, 21, 20, 40, 41, 22, 21, 41, 42, 23, 22, 42, 43, 24, 23, 43, 44, 25, 24, 44, 45, 26, 25, 45, 46, 27, 26, 46, 47, 28, 27, 47, 48, 29, 28, 48, 49, 30, 29, 49, 50, 31, 30, 50, 51, 32, 31, 51, 52, 33, 32, 52, 53, 34, 33, 53, 54, 35, 34, 54, 55, 36, 35, 55, 56, 37, 36, 56, 57, 38, 37, 57, 58, 39, 38, 58, 59, 20, 39, 59, 40, 41, 40, 60, 61, 42, 41, 61, 62, 43, 42, 62, 63, 44, 43, 63, 64, 45, 44, 64, 65, 46, 45, 65, 66, 47, 46, 66, 67, 48, 47, 67, 68, 49, 48, 68, 69, 50, 49, 69, 70, 51, 50, 70, 71, 52, 51, 71, 72, 53, 52, 72, 73, 54, 53, 73, 74, 55, 54, 74, 75, 56, 55, 75, 76, 57, 56, 76, 77, 58, 57, 77, 78, 59, 58, 78, 79, 40, 59, 79, 60, 61, 60, 80, 81, 62, 61, 81, 82, 63, 62, 82, 83, 64, 63, 83, 84, 65, 64, 84, 85, 66, 65, 85, 86, 67, 66, 86, 87, 68, 67, 87, 88, 69, 68, 88, 89, 70, 69, 89, 90, 71, 70, 90, 91, 72, 71, 91, 92, 73, 72, 92, 93, 74, 73, 93, 94, 75, 74, 94, 95, 76, 75, 95, 96, 77, 76, 96, 97, 78, 77, 97, 98, 79, 78, 98, 99, 60, 79, 99, 80, 81, 80, 100, 101, 82, 81, 101, 102, 83, 82, 102, 103, 84, 83, 103, 104, 85, 84, 104, 105, 86, 85, 105, 106, 87, 86, 106, 107, 88, 87, 107, 108, 89, 88, 108, 109, 90, 89, 109, 110, 91, 90, 110, 111, 92, 91, 111, 112, 93, 92, 112, 113, 94, 93, 113, 114, 95, 94, 114, 115, 96, 95, 115, 116, 97, 96, 116, 117, 98, 97, 117, 118, 99, 98, 118, 119, 80, 99, 119, 100, 101, 100, 120, 121, 102, 101, 121, 122, 103, 102, 122, 123, 104, 103, 123, 124, 105, 104, 124, 125, 106, 105, 125, 126, 107, 106, 126, 127, 108, 107, 127, 128, 109, 108, 128, 129, 110, 109, 129, 130, 111, 110, 130, 131, 112, 111, 131, 132, 113, 112, 132, 133, 114, 113, 133, 134, 115, 114, 134, 135, 116, 115, 135, 136, 117, 116, 136, 137, 118, 117, 137, 138, 119, 118, 138, 139, 100, 119, 139, 120, 121, 120, 140, 141, 122, 121, 141, 142, 123, 122, 142, 143, 124, 123, 143, 144, 125, 124, 144, 145, 126, 125, 145, 146, 127, 126, 146, 147, 128, 127, 147, 148, 129, 128, 148, 149, 130, 129, 149, 150, 131, 130, 150, 151, 132, 131, 151, 152, 133, 132, 152, 153, 134, 133, 153, 154, 135, 134, 154, 155, 136, 135, 155, 156, 137, 136, 156, 157, 138, 137, 157, 158, 139, 138, 158, 159, 120, 139, 159, 140, 141, 140, 160, 161, 142, 141, 161, 162, 143, 142, 162, 163, 144, 143, 163, 164, 145, 144, 164, 165, 146, 145, 165, 166, 147, 146, 166, 167, 148, 147, 167, 168, 149, 148, 168, 169, 150, 149, 169, 170, 151, 150, 170, 171, 152, 151, 171, 172, 153, 152, 172, 173, 154, 153, 173, 174, 155, 154, 174, 175, 156, 155, 175, 176, 157, 156, 176, 177, 158, 157, 177, 178, 159, 158, 178, 179, 140, 159, 179, 160, 161, 160, 180, 181, 162, 161, 181, 182, 163, 162, 182, 183, 164, 163, 183, 184, 165, 164, 184, 185, 166, 165, 185, 186, 167, 166, 186, 187, 168, 167, 187, 188, 169, 168, 188, 189, 170, 169, 189, 190, 171, 170, 190, 191, 172, 171, 191, 192, 173, 172, 192, 193, 174, 173, 193, 194, 175, 174, 194, 195, 176, 175, 195, 196, 177, 176, 196, 197, 178, 177, 197, 198, 179, 178, 198, 199, 160, 179, 199, 180, 181, 180, 200, 201, 182, 181, 201, 202, 183, 182, 202, 203, 184, 183, 203, 204, 185, 184, 204, 205, 186, 185, 205, 206, 187, 186, 206, 207, 188, 187, 207, 208, 189, 188, 208, 209, 190, 189, 209, 210, 191, 190, 210, 211, 192, 191, 211, 212, 193, 192, 212, 213, 194, 193, 213, 214, 195, 194, 214, 215, 196, 195, 215, 216, 197, 196, 216, 217, 198, 197, 217, 218, 199, 198, 218, 219, 180, 199, 219, 200, 201, 200, 220, 221, 202, 201, 221, 222, 203, 202, 222, 223, 204, 203, 223, 224, 205, 204, 224, 225, 206, 205, 225, 226, 207, 206, 226, 227, 208, 207, 227, 228, 209, 208, 228, 229, 210, 209, 229, 230, 211, 210, 230, 231, 212, 211, 231, 232, 213, 212, 232, 233, 214, 213, 233, 234, 215, 214, 234, 235, 216, 215, 235, 236, 217, 216, 236, 237, 218, 217, 237, 238, 219, 218, 238, 239, 200, 219, 239, 220, 221, 220, 240, 241, 222, 221, 241, 242, 223, 222, 242, 243, 224, 223, 243, 244, 225, 224, 244, 245, 226, 225, 245, 246, 227, 226, 246, 247, 228, 227, 247, 248, 229, 228, 248, 249, 230, 229, 249, 250, 231, 230, 250, 251, 232, 231, 251, 252, 233, 232, 252, 253, 234, 233, 253, 254, 235, 234, 254, 255, 236, 235, 255, 256, 237, 236, 256, 257, 238, 237, 257, 258, 239, 238, 258, 259, 220, 239, 259, 240, 241, 240, 260, 261, 242, 241, 261, 262, 243, 242, 262, 263, 244, 243, 263, 264, 245, 244, 264, 265, 246, 245, 265, 266, 247, 246, 266, 267, 248, 247, 267, 268, 249, 248, 268, 269, 250, 249, 269, 270, 251, 250, 270, 271, 252, 251, 271, 272, 253, 252, 272, 273, 254, 253, 273, 274, 255, 254, 274, 275, 256, 255, 275, 276, 257, 256, 276, 277, 258, 257, 277, 278, 259, 258, 278, 279, 240, 259, 279, 260, 261, 260, 280, 281, 262, 261, 281, 282, 263, 262, 282, 283, 264, 263, 283, 284, 265, 264, 284, 285, 266, 265, 285, 286, 267, 266, 286, 287, 268, 267, 287, 288, 269, 268, 288, 289, 270, 269, 289, 290, 271, 270, 290, 291, 272, 271, 291, 292, 273, 272, 292, 293, 274, 273, 293, 294, 275, 274, 294, 295, 276, 275, 295, 296, 277, 276, 296, 297, 278, 277, 297, 298, 279, 278, 298, 299, 260, 279, 299, 280, 281, 280, 300, 301, 282, 281, 301, 302, 283, 282, 302, 303, 284, 283, 303, 304, 285, 284, 304, 305, 286, 285, 305, 306, 287, 286, 306, 307, 288, 287, 307, 308, 289, 288, 308, 309, 290, 289, 309, 310, 291, 290, 310, 311, 292, 291, 311, 312, 293, 292, 312, 313, 294, 293, 313, 314, 295, 294, 314, 315, 296, 295, 315, 316, 297, 296, 316, 317, 298, 297, 317, 318, 299, 298, 318, 319, 280, 299, 319, 300, 301, 300, 320, 321, 302, 301, 321, 322, 303, 302, 322, 323, 304, 303, 323, 324, 305, 304, 324, 325, 306, 305, 325, 326, 307, 306, 326, 327, 308, 307, 327, 328, 309, 308, 328, 329, 310, 309, 329, 330, 311, 310, 330, 331, 312, 311, 331, 332, 313, 312, 332, 333, 314, 313, 333, 334, 315, 314, 334, 335, 316, 315, 335, 336, 317, 316, 336, 337, 318, 317, 337, 338, 319, 318, 338, 339, 300, 319, 339, 320, 321, 320, 340, 341, 322, 321, 341, 342, 323, 322, 342, 343, 324, 323, 343, 344, 325, 324, 344, 345, 326, 325, 345, 346, 327, 326, 346, 347, 328, 327, 347, 348, 329, 328, 348, 349, 330, 329, 349, 350, 331, 330, 350, 351, 332, 331, 351, 352, 333, 332, 352, 353, 334, 333, 353, 354, 335, 334, 354, 355, 336, 335, 355, 356, 337, 336, 356, 357, 338, 337, 357, 358, 339, 338, 358, 359, 320, 339, 359, 340, 341, 340, 360, 361, 342, 341, 361, 362, 343, 342, 362, 363, 344, 343, 363, 364, 345, 344, 364, 365, 346, 345, 365, 366, 347, 346, 366, 367, 348, 347, 367, 368, 349, 348, 368, 369, 350, 349, 369, 370, 351, 350, 370, 371, 352, 351, 371, 372, 353, 352, 372, 373, 354, 353, 373, 374, 355, 354, 374, 375, 356, 355, 375, 376, 357, 356, 376, 377, 358, 357, 377, 378, 359, 358, 378, 379, 340, 359, 379, 360, 361, 360, 380, 381, 362, 361, 381, 382, 363, 362, 382, 383, 364, 363, 383, 384, 365, 364, 384, 385, 366, 365, 385, 386, 367, 366, 386, 387, 368, 367, 387, 388, 369, 368, 388, 389, 370, 369, 389, 390, 371, 370, 390, 391, 372, 371, 391, 392, 373, 372, 392, 393, 374, 373, 393, 394, 375, 374, 394, 395, 376, 375, 395, 396, 377, 376, 396, 397, 378, 377, 397, 398, 379, 378, 398, 399, 360, 379, 399, 380, 381, 380, 0, 1, 382, 381, 1, 2, 383, 382, 2, 3, 384, 383, 3, 4, 385, 384, 4, 5, 386, 385, 5, 6, 387, 386, 6, 7, 388, 387, 7, 8, 389, 388, 8, 9, 390, 389, 9, 10, 391, 390, 10, 11, 392, 391, 11, 12, 393, 392, 12, 13, 394, 393, 13, 14, 395, 394, 14, 15, 396, 395, 15, 16, 397, 396, 16, 17, 398, 397, 17, 18, 399, 398, 18, 19, 380, 399, 19, 0] + token interpolateBoundary = "edgeAndCorner" + uniform token orientation = "rightHanded" + float3[] points = [(0.475529, 0, -0.154509), (0.404509, 0, -0.293893), (0.293893, 0, -0.404509), (0.154509, 0, -0.475529), (0, 0, -0.5), (-0.154509, 0, -0.475528), (-0.293893, 0, -0.404509), (-0.404509, 0, -0.293893), (-0.475528, 0, -0.154509), (-0.5, 0, 0), (-0.475528, 0, 0.154509), (-0.404509, 0, 0.293893), (-0.293893, 0, 0.404509), (-0.154509, 0, 0.475528), (-1.49012e-08, 0, 0.5), (0.154508, 0, 0.475528), (0.293893, 0, 0.404509), (0.404509, 0, 0.293893), (0.475528, 0, 0.154509), (0.5, 0, 0), (0.498803, 0.154509, -0.162071), (0.424307, 0.154509, -0.308277), (0.308277, 0.154509, -0.424307), (0.162071, 0.154509, -0.498803), (0, 0.154509, -0.524472), (-0.162071, 0.154509, -0.498803), (-0.308277, 0.154509, -0.424307), (-0.424307, 0.154509, -0.308277), (-0.498802, 0.154509, -0.162071), (-0.524472, 0.154509, 0), (-0.498802, 0.154509, 0.162071), (-0.424307, 0.154509, 0.308277), (-0.308277, 0.154509, 0.424307), (-0.162071, 0.154509, 0.498802), (-1.56305e-08, 0.154509, 0.524472), (0.162071, 0.154509, 0.498802), (0.308277, 0.154509, 0.424307), (0.424307, 0.154509, 0.308277), (0.498802, 0.154509, 0.162071), (0.524472, 0.154509, 0), (0.566346, 0.293893, -0.184017), (0.481763, 0.293893, -0.350021), (0.350021, 0.293893, -0.481763), (0.184017, 0.293893, -0.566346), (0, 0.293893, -0.595492), (-0.184017, 0.293893, -0.566346), (-0.350021, 0.293893, -0.481763), (-0.481763, 0.293893, -0.350021), (-0.566346, 0.293893, -0.184017), (-0.595492, 0.293893, 0), (-0.566346, 0.293893, 0.184017), (-0.481763, 0.293893, 0.350021), (-0.350021, 0.293893, 0.481763), (-0.184017, 0.293893, 0.566346), (-1.7747e-08, 0.293893, 0.595492), (0.184017, 0.293893, 0.566346), (0.350021, 0.293893, 0.481763), (0.481763, 0.293893, 0.350021), (0.566346, 0.293893, 0.184017), (0.595492, 0.293893, 0), (0.671548, 0.404509, -0.218199), (0.571253, 0.404509, -0.41504), (0.41504, 0.404509, -0.571253), (0.218199, 0.404509, -0.671548), (0, 0.404509, -0.706108), (-0.218199, 0.404509, -0.671548), (-0.41504, 0.404509, -0.571253), (-0.571253, 0.404509, -0.41504), (-0.671548, 0.404509, -0.218199), (-0.706108, 0.404509, 0), (-0.671548, 0.404509, 0.218199), (-0.571253, 0.404509, 0.41504), (-0.41504, 0.404509, 0.571253), (-0.218199, 0.404509, 0.671548), (-2.10436e-08, 0.404509, 0.706107), (0.218199, 0.404509, 0.671548), (0.41504, 0.404509, 0.571253), (0.571253, 0.404509, 0.41504), (0.671548, 0.404509, 0.218199), (0.706107, 0.404509, 0), (0.804111, 0.475528, -0.261271), (0.684017, 0.475528, -0.496968), (0.496968, 0.475528, -0.684017), (0.261271, 0.475528, -0.804111), (0, 0.475528, -0.845492), (-0.261271, 0.475528, -0.804111), (-0.496968, 0.475528, -0.684017), (-0.684017, 0.475528, -0.496968), (-0.80411, 0.475528, -0.261271), (-0.845492, 0.475528, 0), (-0.80411, 0.475528, 0.261271), (-0.684017, 0.475528, 0.496968), (-0.496968, 0.475528, 0.684017), (-0.261271, 0.475528, 0.80411), (-2.51976e-08, 0.475528, 0.845492), (0.261271, 0.475528, 0.80411), (0.496967, 0.475528, 0.684017), (0.684017, 0.475528, 0.496967), (0.80411, 0.475528, 0.261271), (0.845492, 0.475528, 0), (0.951057, 0.5, -0.309017), (0.809018, 0.5, -0.587786), (0.587786, 0.5, -0.809017), (0.309017, 0.5, -0.951057), (0, 0.5, -1), (-0.309017, 0.5, -0.951057), (-0.587785, 0.5, -0.809017), (-0.809017, 0.5, -0.587785), (-0.951057, 0.5, -0.309017), (-1, 0.5, 0), (-0.951057, 0.5, 0.309017), (-0.809017, 0.5, 0.587785), (-0.587785, 0.5, 0.809017), (-0.309017, 0.5, 0.951057), (-2.98023e-08, 0.5, 1), (0.309017, 0.5, 0.951057), (0.587785, 0.5, 0.809017), (0.809017, 0.5, 0.587785), (0.951057, 0.5, 0.309017), (1, 0.5, 0), (1.098, 0.475528, -0.356763), (0.934018, 0.475528, -0.678604), (0.678604, 0.475528, -0.934018), (0.356763, 0.475528, -1.098), (0, 0.475528, -1.15451), (-0.356763, 0.475528, -1.098), (-0.678603, 0.475528, -0.934017), (-0.934017, 0.475528, -0.678603), (-1.098, 0.475528, -0.356763), (-1.15451, 0.475528, 0), (-1.098, 0.475528, 0.356763), (-0.934017, 0.475528, 0.678603), (-0.678603, 0.475528, 0.934017), (-0.356763, 0.475528, 1.098), (-3.4407e-08, 0.475528, 1.15451), (0.356763, 0.475528, 1.098), (0.678603, 0.475528, 0.934017), (0.934017, 0.475528, 0.678603), (1.098, 0.475528, 0.356763), (1.15451, 0.475528, 0), (1.23057, 0.404509, -0.399835), (1.04678, 0.404509, -0.760531), (0.760531, 0.404509, -1.04678), (0.399835, 0.404509, -1.23057), (0, 0.404509, -1.29389), (-0.399835, 0.404509, -1.23057), (-0.760531, 0.404509, -1.04678), (-1.04678, 0.404509, -0.760531), (-1.23057, 0.404509, -0.399835), (-1.29389, 0.404509, 0), (-1.23057, 0.404509, 0.399835), (-1.04678, 0.404509, 0.760531), (-0.760531, 0.404509, 1.04678), (-0.399835, 0.404509, 1.23057), (-3.8561e-08, 0.404509, 1.29389), (0.399835, 0.404509, 1.23057), (0.760531, 0.404509, 1.04678), (1.04678, 0.404509, 0.760531), (1.23057, 0.404509, 0.399835), (1.29389, 0.404509, 0), (1.33577, 0.293893, -0.434017), (1.13627, 0.293893, -0.82555), (0.82555, 0.293893, -1.13627), (0.434017, 0.293893, -1.33577), (0, 0.293893, -1.40451), (-0.434017, 0.293893, -1.33577), (-0.82555, 0.293893, -1.13627), (-1.13627, 0.293893, -0.82555), (-1.33577, 0.293893, -0.434017), (-1.40451, 0.293893, 0), (-1.33577, 0.293893, 0.434017), (-1.13627, 0.293893, 0.82555), (-0.82555, 0.293893, 1.13627), (-0.434017, 0.293893, 1.33577), (-4.18576e-08, 0.293893, 1.40451), (0.434017, 0.293893, 1.33577), (0.825549, 0.293893, 1.13627), (1.13627, 0.293893, 0.825549), (1.33577, 0.293893, 0.434017), (1.40451, 0.293893, 0), (1.40331, 0.154509, -0.455964), (1.19373, 0.154509, -0.867294), (0.867294, 0.154509, -1.19373), (0.455964, 0.154509, -1.40331), (0, 0.154509, -1.47553), (-0.455964, 0.154509, -1.40331), (-0.867294, 0.154509, -1.19373), (-1.19373, 0.154509, -0.867294), (-1.40331, 0.154509, -0.455963), (-1.47553, 0.154509, 0), (-1.40331, 0.154509, 0.455963), (-1.19373, 0.154509, 0.867294), (-0.867294, 0.154509, 1.19373), (-0.455963, 0.154509, 1.40331), (-4.39742e-08, 0.154509, 1.47553), (0.455963, 0.154509, 1.40331), (0.867294, 0.154509, 1.19373), (1.19373, 0.154509, 0.867294), (1.40331, 0.154509, 0.455963), (1.47553, 0.154509, 0), (1.42659, 0, -0.463526), (1.21353, 0, -0.881678), (0.881678, 0, -1.21353), (0.463526, 0, -1.42659), (0, 0, -1.5), (-0.463526, 0, -1.42659), (-0.881678, 0, -1.21353), (-1.21353, 0, -0.881678), (-1.42659, 0, -0.463526), (-1.5, 0, 0), (-1.42659, 0, 0.463526), (-1.21353, 0, 0.881678), (-0.881678, 0, 1.21353), (-0.463526, 0, 1.42659), (-4.47035e-08, 0, 1.5), (0.463526, 0, 1.42658), (0.881678, 0, 1.21353), (1.21353, 0, 0.881678), (1.42658, 0, 0.463526), (1.5, 0, 0), (1.40331, -0.154509, -0.455964), (1.19373, -0.154509, -0.867294), (0.867294, -0.154509, -1.19373), (0.455964, -0.154509, -1.40331), (0, -0.154509, -1.47553), (-0.455964, -0.154509, -1.40331), (-0.867294, -0.154509, -1.19373), (-1.19373, -0.154509, -0.867294), (-1.40331, -0.154509, -0.455963), (-1.47553, -0.154509, 0), (-1.40331, -0.154509, 0.455963), (-1.19373, -0.154509, 0.867294), (-0.867294, -0.154509, 1.19373), (-0.455963, -0.154509, 1.40331), (-4.39742e-08, -0.154509, 1.47553), (0.455963, -0.154509, 1.40331), (0.867294, -0.154509, 1.19373), (1.19373, -0.154509, 0.867294), (1.40331, -0.154509, 0.455963), (1.47553, -0.154509, 0), (1.33577, -0.293893, -0.434017), (1.13627, -0.293893, -0.82555), (0.82555, -0.293893, -1.13627), (0.434017, -0.293893, -1.33577), (0, -0.293893, -1.40451), (-0.434017, -0.293893, -1.33577), (-0.82555, -0.293893, -1.13627), (-1.13627, -0.293893, -0.82555), (-1.33577, -0.293893, -0.434017), (-1.40451, -0.293893, 0), (-1.33577, -0.293893, 0.434017), (-1.13627, -0.293893, 0.82555), (-0.82555, -0.293893, 1.13627), (-0.434017, -0.293893, 1.33577), (-4.18576e-08, -0.293893, 1.40451), (0.434017, -0.293893, 1.33577), (0.825549, -0.293893, 1.13627), (1.13627, -0.293893, 0.825549), (1.33577, -0.293893, 0.434017), (1.40451, -0.293893, 0), (1.23057, -0.404509, -0.399835), (1.04678, -0.404509, -0.760532), (0.760532, -0.404509, -1.04678), (0.399835, -0.404509, -1.23057), (0, -0.404509, -1.29389), (-0.399835, -0.404509, -1.23057), (-0.760531, -0.404509, -1.04678), (-1.04678, -0.404509, -0.760531), (-1.23057, -0.404509, -0.399835), (-1.29389, -0.404509, 0), (-1.23057, -0.404509, 0.399835), (-1.04678, -0.404509, 0.760531), (-0.760531, -0.404509, 1.04678), (-0.399835, -0.404509, 1.23057), (-3.8561e-08, -0.404509, 1.29389), (0.399835, -0.404509, 1.23057), (0.760531, -0.404509, 1.04678), (1.04678, -0.404509, 0.760531), (1.23057, -0.404509, 0.399835), (1.29389, -0.404509, 0), (1.098, -0.475528, -0.356763), (0.934018, -0.475528, -0.678604), (0.678604, -0.475528, -0.934018), (0.356763, -0.475528, -1.098), (0, -0.475528, -1.15451), (-0.356763, -0.475528, -1.098), (-0.678603, -0.475528, -0.934017), (-0.934017, -0.475528, -0.678603), (-1.098, -0.475528, -0.356763), (-1.15451, -0.475528, 0), (-1.098, -0.475528, 0.356763), (-0.934017, -0.475528, 0.678603), (-0.678603, -0.475528, 0.934017), (-0.356763, -0.475528, 1.098), (-3.4407e-08, -0.475528, 1.15451), (0.356763, -0.475528, 1.098), (0.678603, -0.475528, 0.934017), (0.934017, -0.475528, 0.678603), (1.098, -0.475528, 0.356763), (1.15451, -0.475528, 0), (0.951057, -0.5, -0.309017), (0.809018, -0.5, -0.587786), (0.587786, -0.5, -0.809017), (0.309017, -0.5, -0.951057), (0, -0.5, -1), (-0.309017, -0.5, -0.951057), (-0.587785, -0.5, -0.809017), (-0.809017, -0.5, -0.587785), (-0.951057, -0.5, -0.309017), (-1, -0.5, 0), (-0.951057, -0.5, 0.309017), (-0.809017, -0.5, 0.587785), (-0.587785, -0.5, 0.809017), (-0.309017, -0.5, 0.951057), (-2.98023e-08, -0.5, 1), (0.309017, -0.5, 0.951057), (0.587785, -0.5, 0.809017), (0.809017, -0.5, 0.587785), (0.951057, -0.5, 0.309017), (1, -0.5, 0), (0.804111, -0.475529, -0.261271), (0.684017, -0.475529, -0.496968), (0.496968, -0.475529, -0.684017), (0.261271, -0.475529, -0.804111), (0, -0.475529, -0.845492), (-0.261271, -0.475529, -0.80411), (-0.496968, -0.475529, -0.684017), (-0.684017, -0.475529, -0.496968), (-0.80411, -0.475529, -0.261271), (-0.845492, -0.475529, 0), (-0.80411, -0.475529, 0.261271), (-0.684017, -0.475529, 0.496967), (-0.496967, -0.475529, 0.684017), (-0.261271, -0.475529, 0.80411), (-2.51976e-08, -0.475529, 0.845492), (0.261271, -0.475529, 0.80411), (0.496967, -0.475529, 0.684017), (0.684017, -0.475529, 0.496967), (0.80411, -0.475529, 0.261271), (0.845491, -0.475529, 0), (0.671548, -0.404509, -0.218199), (0.571253, -0.404509, -0.41504), (0.41504, -0.404509, -0.571253), (0.218199, -0.404509, -0.671548), (0, -0.404509, -0.706108), (-0.218199, -0.404509, -0.671548), (-0.41504, -0.404509, -0.571253), (-0.571253, -0.404509, -0.41504), (-0.671548, -0.404509, -0.218199), (-0.706107, -0.404509, 0), (-0.671548, -0.404509, 0.218199), (-0.571253, -0.404509, 0.415039), (-0.415039, -0.404509, 0.571253), (-0.218199, -0.404509, 0.671548), (-2.10436e-08, -0.404509, 0.706107), (0.218199, -0.404509, 0.671548), (0.415039, -0.404509, 0.571253), (0.571253, -0.404509, 0.415039), (0.671548, -0.404509, 0.218199), (0.706107, -0.404509, 0), (0.566346, -0.293893, -0.184017), (0.481763, -0.293893, -0.350021), (0.350021, -0.293893, -0.481763), (0.184017, -0.293893, -0.566346), (0, -0.293893, -0.595492), (-0.184017, -0.293893, -0.566346), (-0.350021, -0.293893, -0.481763), (-0.481763, -0.293893, -0.350021), (-0.566346, -0.293893, -0.184017), (-0.595491, -0.293893, 0), (-0.566346, -0.293893, 0.184017), (-0.481763, -0.293893, 0.350021), (-0.350021, -0.293893, 0.481763), (-0.184017, -0.293893, 0.566346), (-1.7747e-08, -0.293893, 0.595491), (0.184017, -0.293893, 0.566346), (0.350021, -0.293893, 0.481763), (0.481763, -0.293893, 0.350021), (0.566346, -0.293893, 0.184017), (0.595491, -0.293893, 0), (0.498802, -0.154509, -0.162071), (0.424307, -0.154509, -0.308277), (0.308277, -0.154509, -0.424307), (0.162071, -0.154509, -0.498802), (0, -0.154509, -0.524472), (-0.162071, -0.154509, -0.498802), (-0.308277, -0.154509, -0.424306), (-0.424306, -0.154509, -0.308277), (-0.498802, -0.154509, -0.162071), (-0.524472, -0.154509, 0), (-0.498802, -0.154509, 0.162071), (-0.424306, -0.154509, 0.308277), (-0.308277, -0.154509, 0.424306), (-0.162071, -0.154509, 0.498802), (-1.56305e-08, -0.154509, 0.524471), (0.162071, -0.154509, 0.498802), (0.308277, -0.154509, 0.424306), (0.424306, -0.154509, 0.308277), (0.498802, -0.154509, 0.162071), (0.524471, -0.154509, 0)] + string primvars:__handleid = "${user:ModelInstance}_pTorus1" ( + interpolation = "constant" + ) + color3f[] primvars:displayColor = [(0.217638, 0.217638, 0.217638)] + float3[] primvars:ModelBuildRefPose = [(0.475529, 0, -0.154509), (0.404509, 0, -0.293893), (0.293893, 0, -0.404509), (0.154509, 0, -0.475529), (0, 0, -0.5), (-0.154509, 0, -0.475528), (-0.293893, 0, -0.404509), (-0.404509, 0, -0.293893), (-0.475528, 0, -0.154509), (-0.5, 0, 0), (-0.475528, 0, 0.154509), (-0.404509, 0, 0.293893), (-0.293893, 0, 0.404509), (-0.154509, 0, 0.475528), (-1.49012e-08, 0, 0.5), (0.154508, 0, 0.475528), (0.293893, 0, 0.404509), (0.404509, 0, 0.293893), (0.475528, 0, 0.154509), (0.5, 0, 0), (0.498803, 0.154509, -0.162071), (0.424307, 0.154509, -0.308277), (0.308277, 0.154509, -0.424307), (0.162071, 0.154509, -0.498803), (0, 0.154509, -0.524472), (-0.162071, 0.154509, -0.498803), (-0.308277, 0.154509, -0.424307), (-0.424307, 0.154509, -0.308277), (-0.498802, 0.154509, -0.162071), (-0.524472, 0.154509, 0), (-0.498802, 0.154509, 0.162071), (-0.424307, 0.154509, 0.308277), (-0.308277, 0.154509, 0.424307), (-0.162071, 0.154509, 0.498802), (-1.56305e-08, 0.154509, 0.524472), (0.162071, 0.154509, 0.498802), (0.308277, 0.154509, 0.424307), (0.424307, 0.154509, 0.308277), (0.498802, 0.154509, 0.162071), (0.524472, 0.154509, 0), (0.566346, 0.293893, -0.184017), (0.481763, 0.293893, -0.350021), (0.350021, 0.293893, -0.481763), (0.184017, 0.293893, -0.566346), (0, 0.293893, -0.595492), (-0.184017, 0.293893, -0.566346), (-0.350021, 0.293893, -0.481763), (-0.481763, 0.293893, -0.350021), (-0.566346, 0.293893, -0.184017), (-0.595492, 0.293893, 0), (-0.566346, 0.293893, 0.184017), (-0.481763, 0.293893, 0.350021), (-0.350021, 0.293893, 0.481763), (-0.184017, 0.293893, 0.566346), (-1.7747e-08, 0.293893, 0.595492), (0.184017, 0.293893, 0.566346), (0.350021, 0.293893, 0.481763), (0.481763, 0.293893, 0.350021), (0.566346, 0.293893, 0.184017), (0.595492, 0.293893, 0), (0.671548, 0.404509, -0.218199), (0.571253, 0.404509, -0.41504), (0.41504, 0.404509, -0.571253), (0.218199, 0.404509, -0.671548), (0, 0.404509, -0.706108), (-0.218199, 0.404509, -0.671548), (-0.41504, 0.404509, -0.571253), (-0.571253, 0.404509, -0.41504), (-0.671548, 0.404509, -0.218199), (-0.706108, 0.404509, 0), (-0.671548, 0.404509, 0.218199), (-0.571253, 0.404509, 0.41504), (-0.41504, 0.404509, 0.571253), (-0.218199, 0.404509, 0.671548), (-2.10436e-08, 0.404509, 0.706107), (0.218199, 0.404509, 0.671548), (0.41504, 0.404509, 0.571253), (0.571253, 0.404509, 0.41504), (0.671548, 0.404509, 0.218199), (0.706107, 0.404509, 0), (0.804111, 0.475528, -0.261271), (0.684017, 0.475528, -0.496968), (0.496968, 0.475528, -0.684017), (0.261271, 0.475528, -0.804111), (0, 0.475528, -0.845492), (-0.261271, 0.475528, -0.804111), (-0.496968, 0.475528, -0.684017), (-0.684017, 0.475528, -0.496968), (-0.80411, 0.475528, -0.261271), (-0.845492, 0.475528, 0), (-0.80411, 0.475528, 0.261271), (-0.684017, 0.475528, 0.496968), (-0.496968, 0.475528, 0.684017), (-0.261271, 0.475528, 0.80411), (-2.51976e-08, 0.475528, 0.845492), (0.261271, 0.475528, 0.80411), (0.496967, 0.475528, 0.684017), (0.684017, 0.475528, 0.496967), (0.80411, 0.475528, 0.261271), (0.845492, 0.475528, 0), (0.951057, 0.5, -0.309017), (0.809018, 0.5, -0.587786), (0.587786, 0.5, -0.809017), (0.309017, 0.5, -0.951057), (0, 0.5, -1), (-0.309017, 0.5, -0.951057), (-0.587785, 0.5, -0.809017), (-0.809017, 0.5, -0.587785), (-0.951057, 0.5, -0.309017), (-1, 0.5, 0), (-0.951057, 0.5, 0.309017), (-0.809017, 0.5, 0.587785), (-0.587785, 0.5, 0.809017), (-0.309017, 0.5, 0.951057), (-2.98023e-08, 0.5, 1), (0.309017, 0.5, 0.951057), (0.587785, 0.5, 0.809017), (0.809017, 0.5, 0.587785), (0.951057, 0.5, 0.309017), (1, 0.5, 0), (1.098, 0.475528, -0.356763), (0.934018, 0.475528, -0.678604), (0.678604, 0.475528, -0.934018), (0.356763, 0.475528, -1.098), (0, 0.475528, -1.15451), (-0.356763, 0.475528, -1.098), (-0.678603, 0.475528, -0.934017), (-0.934017, 0.475528, -0.678603), (-1.098, 0.475528, -0.356763), (-1.15451, 0.475528, 0), (-1.098, 0.475528, 0.356763), (-0.934017, 0.475528, 0.678603), (-0.678603, 0.475528, 0.934017), (-0.356763, 0.475528, 1.098), (-3.4407e-08, 0.475528, 1.15451), (0.356763, 0.475528, 1.098), (0.678603, 0.475528, 0.934017), (0.934017, 0.475528, 0.678603), (1.098, 0.475528, 0.356763), (1.15451, 0.475528, 0), (1.23057, 0.404509, -0.399835), (1.04678, 0.404509, -0.760531), (0.760531, 0.404509, -1.04678), (0.399835, 0.404509, -1.23057), (0, 0.404509, -1.29389), (-0.399835, 0.404509, -1.23057), (-0.760531, 0.404509, -1.04678), (-1.04678, 0.404509, -0.760531), (-1.23057, 0.404509, -0.399835), (-1.29389, 0.404509, 0), (-1.23057, 0.404509, 0.399835), (-1.04678, 0.404509, 0.760531), (-0.760531, 0.404509, 1.04678), (-0.399835, 0.404509, 1.23057), (-3.8561e-08, 0.404509, 1.29389), (0.399835, 0.404509, 1.23057), (0.760531, 0.404509, 1.04678), (1.04678, 0.404509, 0.760531), (1.23057, 0.404509, 0.399835), (1.29389, 0.404509, 0), (1.33577, 0.293893, -0.434017), (1.13627, 0.293893, -0.82555), (0.82555, 0.293893, -1.13627), (0.434017, 0.293893, -1.33577), (0, 0.293893, -1.40451), (-0.434017, 0.293893, -1.33577), (-0.82555, 0.293893, -1.13627), (-1.13627, 0.293893, -0.82555), (-1.33577, 0.293893, -0.434017), (-1.40451, 0.293893, 0), (-1.33577, 0.293893, 0.434017), (-1.13627, 0.293893, 0.82555), (-0.82555, 0.293893, 1.13627), (-0.434017, 0.293893, 1.33577), (-4.18576e-08, 0.293893, 1.40451), (0.434017, 0.293893, 1.33577), (0.825549, 0.293893, 1.13627), (1.13627, 0.293893, 0.825549), (1.33577, 0.293893, 0.434017), (1.40451, 0.293893, 0), (1.40331, 0.154509, -0.455964), (1.19373, 0.154509, -0.867294), (0.867294, 0.154509, -1.19373), (0.455964, 0.154509, -1.40331), (0, 0.154509, -1.47553), (-0.455964, 0.154509, -1.40331), (-0.867294, 0.154509, -1.19373), (-1.19373, 0.154509, -0.867294), (-1.40331, 0.154509, -0.455963), (-1.47553, 0.154509, 0), (-1.40331, 0.154509, 0.455963), (-1.19373, 0.154509, 0.867294), (-0.867294, 0.154509, 1.19373), (-0.455963, 0.154509, 1.40331), (-4.39742e-08, 0.154509, 1.47553), (0.455963, 0.154509, 1.40331), (0.867294, 0.154509, 1.19373), (1.19373, 0.154509, 0.867294), (1.40331, 0.154509, 0.455963), (1.47553, 0.154509, 0), (1.42659, 0, -0.463526), (1.21353, 0, -0.881678), (0.881678, 0, -1.21353), (0.463526, 0, -1.42659), (0, 0, -1.5), (-0.463526, 0, -1.42659), (-0.881678, 0, -1.21353), (-1.21353, 0, -0.881678), (-1.42659, 0, -0.463526), (-1.5, 0, 0), (-1.42659, 0, 0.463526), (-1.21353, 0, 0.881678), (-0.881678, 0, 1.21353), (-0.463526, 0, 1.42659), (-4.47035e-08, 0, 1.5), (0.463526, 0, 1.42658), (0.881678, 0, 1.21353), (1.21353, 0, 0.881678), (1.42658, 0, 0.463526), (1.5, 0, 0), (1.40331, -0.154509, -0.455964), (1.19373, -0.154509, -0.867294), (0.867294, -0.154509, -1.19373), (0.455964, -0.154509, -1.40331), (0, -0.154509, -1.47553), (-0.455964, -0.154509, -1.40331), (-0.867294, -0.154509, -1.19373), (-1.19373, -0.154509, -0.867294), (-1.40331, -0.154509, -0.455963), (-1.47553, -0.154509, 0), (-1.40331, -0.154509, 0.455963), (-1.19373, -0.154509, 0.867294), (-0.867294, -0.154509, 1.19373), (-0.455963, -0.154509, 1.40331), (-4.39742e-08, -0.154509, 1.47553), (0.455963, -0.154509, 1.40331), (0.867294, -0.154509, 1.19373), (1.19373, -0.154509, 0.867294), (1.40331, -0.154509, 0.455963), (1.47553, -0.154509, 0), (1.33577, -0.293893, -0.434017), (1.13627, -0.293893, -0.82555), (0.82555, -0.293893, -1.13627), (0.434017, -0.293893, -1.33577), (0, -0.293893, -1.40451), (-0.434017, -0.293893, -1.33577), (-0.82555, -0.293893, -1.13627), (-1.13627, -0.293893, -0.82555), (-1.33577, -0.293893, -0.434017), (-1.40451, -0.293893, 0), (-1.33577, -0.293893, 0.434017), (-1.13627, -0.293893, 0.82555), (-0.82555, -0.293893, 1.13627), (-0.434017, -0.293893, 1.33577), (-4.18576e-08, -0.293893, 1.40451), (0.434017, -0.293893, 1.33577), (0.825549, -0.293893, 1.13627), (1.13627, -0.293893, 0.825549), (1.33577, -0.293893, 0.434017), (1.40451, -0.293893, 0), (1.23057, -0.404509, -0.399835), (1.04678, -0.404509, -0.760532), (0.760532, -0.404509, -1.04678), (0.399835, -0.404509, -1.23057), (0, -0.404509, -1.29389), (-0.399835, -0.404509, -1.23057), (-0.760531, -0.404509, -1.04678), (-1.04678, -0.404509, -0.760531), (-1.23057, -0.404509, -0.399835), (-1.29389, -0.404509, 0), (-1.23057, -0.404509, 0.399835), (-1.04678, -0.404509, 0.760531), (-0.760531, -0.404509, 1.04678), (-0.399835, -0.404509, 1.23057), (-3.8561e-08, -0.404509, 1.29389), (0.399835, -0.404509, 1.23057), (0.760531, -0.404509, 1.04678), (1.04678, -0.404509, 0.760531), (1.23057, -0.404509, 0.399835), (1.29389, -0.404509, 0), (1.098, -0.475528, -0.356763), (0.934018, -0.475528, -0.678604), (0.678604, -0.475528, -0.934018), (0.356763, -0.475528, -1.098), (0, -0.475528, -1.15451), (-0.356763, -0.475528, -1.098), (-0.678603, -0.475528, -0.934017), (-0.934017, -0.475528, -0.678603), (-1.098, -0.475528, -0.356763), (-1.15451, -0.475528, 0), (-1.098, -0.475528, 0.356763), (-0.934017, -0.475528, 0.678603), (-0.678603, -0.475528, 0.934017), (-0.356763, -0.475528, 1.098), (-3.4407e-08, -0.475528, 1.15451), (0.356763, -0.475528, 1.098), (0.678603, -0.475528, 0.934017), (0.934017, -0.475528, 0.678603), (1.098, -0.475528, 0.356763), (1.15451, -0.475528, 0), (0.951057, -0.5, -0.309017), (0.809018, -0.5, -0.587786), (0.587786, -0.5, -0.809017), (0.309017, -0.5, -0.951057), (0, -0.5, -1), (-0.309017, -0.5, -0.951057), (-0.587785, -0.5, -0.809017), (-0.809017, -0.5, -0.587785), (-0.951057, -0.5, -0.309017), (-1, -0.5, 0), (-0.951057, -0.5, 0.309017), (-0.809017, -0.5, 0.587785), (-0.587785, -0.5, 0.809017), (-0.309017, -0.5, 0.951057), (-2.98023e-08, -0.5, 1), (0.309017, -0.5, 0.951057), (0.587785, -0.5, 0.809017), (0.809017, -0.5, 0.587785), (0.951057, -0.5, 0.309017), (1, -0.5, 0), (0.804111, -0.475529, -0.261271), (0.684017, -0.475529, -0.496968), (0.496968, -0.475529, -0.684017), (0.261271, -0.475529, -0.804111), (0, -0.475529, -0.845492), (-0.261271, -0.475529, -0.80411), (-0.496968, -0.475529, -0.684017), (-0.684017, -0.475529, -0.496968), (-0.80411, -0.475529, -0.261271), (-0.845492, -0.475529, 0), (-0.80411, -0.475529, 0.261271), (-0.684017, -0.475529, 0.496967), (-0.496967, -0.475529, 0.684017), (-0.261271, -0.475529, 0.80411), (-2.51976e-08, -0.475529, 0.845492), (0.261271, -0.475529, 0.80411), (0.496967, -0.475529, 0.684017), (0.684017, -0.475529, 0.496967), (0.80411, -0.475529, 0.261271), (0.845491, -0.475529, 0), (0.671548, -0.404509, -0.218199), (0.571253, -0.404509, -0.41504), (0.41504, -0.404509, -0.571253), (0.218199, -0.404509, -0.671548), (0, -0.404509, -0.706108), (-0.218199, -0.404509, -0.671548), (-0.41504, -0.404509, -0.571253), (-0.571253, -0.404509, -0.41504), (-0.671548, -0.404509, -0.218199), (-0.706107, -0.404509, 0), (-0.671548, -0.404509, 0.218199), (-0.571253, -0.404509, 0.415039), (-0.415039, -0.404509, 0.571253), (-0.218199, -0.404509, 0.671548), (-2.10436e-08, -0.404509, 0.706107), (0.218199, -0.404509, 0.671548), (0.415039, -0.404509, 0.571253), (0.571253, -0.404509, 0.415039), (0.671548, -0.404509, 0.218199), (0.706107, -0.404509, 0), (0.566346, -0.293893, -0.184017), (0.481763, -0.293893, -0.350021), (0.350021, -0.293893, -0.481763), (0.184017, -0.293893, -0.566346), (0, -0.293893, -0.595492), (-0.184017, -0.293893, -0.566346), (-0.350021, -0.293893, -0.481763), (-0.481763, -0.293893, -0.350021), (-0.566346, -0.293893, -0.184017), (-0.595491, -0.293893, 0), (-0.566346, -0.293893, 0.184017), (-0.481763, -0.293893, 0.350021), (-0.350021, -0.293893, 0.481763), (-0.184017, -0.293893, 0.566346), (-1.7747e-08, -0.293893, 0.595491), (0.184017, -0.293893, 0.566346), (0.350021, -0.293893, 0.481763), (0.481763, -0.293893, 0.350021), (0.566346, -0.293893, 0.184017), (0.595491, -0.293893, 0), (0.498802, -0.154509, -0.162071), (0.424307, -0.154509, -0.308277), (0.308277, -0.154509, -0.424307), (0.162071, -0.154509, -0.498802), (0, -0.154509, -0.524472), (-0.162071, -0.154509, -0.498802), (-0.308277, -0.154509, -0.424306), (-0.424306, -0.154509, -0.308277), (-0.498802, -0.154509, -0.162071), (-0.524472, -0.154509, 0), (-0.498802, -0.154509, 0.162071), (-0.424306, -0.154509, 0.308277), (-0.308277, -0.154509, 0.424306), (-0.162071, -0.154509, 0.498802), (-1.56305e-08, -0.154509, 0.524471), (0.162071, -0.154509, 0.498802), (0.308277, -0.154509, 0.424306), (0.424306, -0.154509, 0.308277), (0.498802, -0.154509, 0.162071), (0.524471, -0.154509, 0)] ( + interpolation = "vertex" + ) + float[] primvars:ptexFaceIndex = [0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63, 64, 64, 64, 64, 65, 65, 65, 65, 66, 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 69, 69, 69, 70, 70, 70, 70, 71, 71, 71, 71, 72, 72, 72, 72, 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, 77, 78, 78, 78, 78, 79, 79, 79, 79, 80, 80, 80, 80, 81, 81, 81, 81, 82, 82, 82, 82, 83, 83, 83, 83, 84, 84, 84, 84, 85, 85, 85, 85, 86, 86, 86, 86, 87, 87, 87, 87, 88, 88, 88, 88, 89, 89, 89, 89, 90, 90, 90, 90, 91, 91, 91, 91, 92, 92, 92, 92, 93, 93, 93, 93, 94, 94, 94, 94, 95, 95, 95, 95, 96, 96, 96, 96, 97, 97, 97, 97, 98, 98, 98, 98, 99, 99, 99, 99, 100, 100, 100, 100, 101, 101, 101, 101, 102, 102, 102, 102, 103, 103, 103, 103, 104, 104, 104, 104, 105, 105, 105, 105, 106, 106, 106, 106, 107, 107, 107, 107, 108, 108, 108, 108, 109, 109, 109, 109, 110, 110, 110, 110, 111, 111, 111, 111, 112, 112, 112, 112, 113, 113, 113, 113, 114, 114, 114, 114, 115, 115, 115, 115, 116, 116, 116, 116, 117, 117, 117, 117, 118, 118, 118, 118, 119, 119, 119, 119, 120, 120, 120, 120, 121, 121, 121, 121, 122, 122, 122, 122, 123, 123, 123, 123, 124, 124, 124, 124, 125, 125, 125, 125, 126, 126, 126, 126, 127, 127, 127, 127, 128, 128, 128, 128, 129, 129, 129, 129, 130, 130, 130, 130, 131, 131, 131, 131, 132, 132, 132, 132, 133, 133, 133, 133, 134, 134, 134, 134, 135, 135, 135, 135, 136, 136, 136, 136, 137, 137, 137, 137, 138, 138, 138, 138, 139, 139, 139, 139, 140, 140, 140, 140, 141, 141, 141, 141, 142, 142, 142, 142, 143, 143, 143, 143, 144, 144, 144, 144, 145, 145, 145, 145, 146, 146, 146, 146, 147, 147, 147, 147, 148, 148, 148, 148, 149, 149, 149, 149, 150, 150, 150, 150, 151, 151, 151, 151, 152, 152, 152, 152, 153, 153, 153, 153, 154, 154, 154, 154, 155, 155, 155, 155, 156, 156, 156, 156, 157, 157, 157, 157, 158, 158, 158, 158, 159, 159, 159, 159, 160, 160, 160, 160, 161, 161, 161, 161, 162, 162, 162, 162, 163, 163, 163, 163, 164, 164, 164, 164, 165, 165, 165, 165, 166, 166, 166, 166, 167, 167, 167, 167, 168, 168, 168, 168, 169, 169, 169, 169, 170, 170, 170, 170, 171, 171, 171, 171, 172, 172, 172, 172, 173, 173, 173, 173, 174, 174, 174, 174, 175, 175, 175, 175, 176, 176, 176, 176, 177, 177, 177, 177, 178, 178, 178, 178, 179, 179, 179, 179, 180, 180, 180, 180, 181, 181, 181, 181, 182, 182, 182, 182, 183, 183, 183, 183, 184, 184, 184, 184, 185, 185, 185, 185, 186, 186, 186, 186, 187, 187, 187, 187, 188, 188, 188, 188, 189, 189, 189, 189, 190, 190, 190, 190, 191, 191, 191, 191, 192, 192, 192, 192, 193, 193, 193, 193, 194, 194, 194, 194, 195, 195, 195, 195, 196, 196, 196, 196, 197, 197, 197, 197, 198, 198, 198, 198, 199, 199, 199, 199, 200, 200, 200, 200, 201, 201, 201, 201, 202, 202, 202, 202, 203, 203, 203, 203, 204, 204, 204, 204, 205, 205, 205, 205, 206, 206, 206, 206, 207, 207, 207, 207, 208, 208, 208, 208, 209, 209, 209, 209, 210, 210, 210, 210, 211, 211, 211, 211, 212, 212, 212, 212, 213, 213, 213, 213, 214, 214, 214, 214, 215, 215, 215, 215, 216, 216, 216, 216, 217, 217, 217, 217, 218, 218, 218, 218, 219, 219, 219, 219, 220, 220, 220, 220, 221, 221, 221, 221, 222, 222, 222, 222, 223, 223, 223, 223, 224, 224, 224, 224, 225, 225, 225, 225, 226, 226, 226, 226, 227, 227, 227, 227, 228, 228, 228, 228, 229, 229, 229, 229, 230, 230, 230, 230, 231, 231, 231, 231, 232, 232, 232, 232, 233, 233, 233, 233, 234, 234, 234, 234, 235, 235, 235, 235, 236, 236, 236, 236, 237, 237, 237, 237, 238, 238, 238, 238, 239, 239, 239, 239, 240, 240, 240, 240, 241, 241, 241, 241, 242, 242, 242, 242, 243, 243, 243, 243, 244, 244, 244, 244, 245, 245, 245, 245, 246, 246, 246, 246, 247, 247, 247, 247, 248, 248, 248, 248, 249, 249, 249, 249, 250, 250, 250, 250, 251, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254, 254, 254, 254, 255, 255, 255, 255, 256, 256, 256, 256, 257, 257, 257, 257, 258, 258, 258, 258, 259, 259, 259, 259, 260, 260, 260, 260, 261, 261, 261, 261, 262, 262, 262, 262, 263, 263, 263, 263, 264, 264, 264, 264, 265, 265, 265, 265, 266, 266, 266, 266, 267, 267, 267, 267, 268, 268, 268, 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, 272, 272, 273, 273, 273, 273, 274, 274, 274, 274, 275, 275, 275, 275, 276, 276, 276, 276, 277, 277, 277, 277, 278, 278, 278, 278, 279, 279, 279, 279, 280, 280, 280, 280, 281, 281, 281, 281, 282, 282, 282, 282, 283, 283, 283, 283, 284, 284, 284, 284, 285, 285, 285, 285, 286, 286, 286, 286, 287, 287, 287, 287, 288, 288, 288, 288, 289, 289, 289, 289, 290, 290, 290, 290, 291, 291, 291, 291, 292, 292, 292, 292, 293, 293, 293, 293, 294, 294, 294, 294, 295, 295, 295, 295, 296, 296, 296, 296, 297, 297, 297, 297, 298, 298, 298, 298, 299, 299, 299, 299, 300, 300, 300, 300, 301, 301, 301, 301, 302, 302, 302, 302, 303, 303, 303, 303, 304, 304, 304, 304, 305, 305, 305, 305, 306, 306, 306, 306, 307, 307, 307, 307, 308, 308, 308, 308, 309, 309, 309, 309, 310, 310, 310, 310, 311, 311, 311, 311, 312, 312, 312, 312, 313, 313, 313, 313, 314, 314, 314, 314, 315, 315, 315, 315, 316, 316, 316, 316, 317, 317, 317, 317, 318, 318, 318, 318, 319, 319, 319, 319, 320, 320, 320, 320, 321, 321, 321, 321, 322, 322, 322, 322, 323, 323, 323, 323, 324, 324, 324, 324, 325, 325, 325, 325, 326, 326, 326, 326, 327, 327, 327, 327, 328, 328, 328, 328, 329, 329, 329, 329, 330, 330, 330, 330, 331, 331, 331, 331, 332, 332, 332, 332, 333, 333, 333, 333, 334, 334, 334, 334, 335, 335, 335, 335, 336, 336, 336, 336, 337, 337, 337, 337, 338, 338, 338, 338, 339, 339, 339, 339, 340, 340, 340, 340, 341, 341, 341, 341, 342, 342, 342, 342, 343, 343, 343, 343, 344, 344, 344, 344, 345, 345, 345, 345, 346, 346, 346, 346, 347, 347, 347, 347, 348, 348, 348, 348, 349, 349, 349, 349, 350, 350, 350, 350, 351, 351, 351, 351, 352, 352, 352, 352, 353, 353, 353, 353, 354, 354, 354, 354, 355, 355, 355, 355, 356, 356, 356, 356, 357, 357, 357, 357, 358, 358, 358, 358, 359, 359, 359, 359, 360, 360, 360, 360, 361, 361, 361, 361, 362, 362, 362, 362, 363, 363, 363, 363, 364, 364, 364, 364, 365, 365, 365, 365, 366, 366, 366, 366, 367, 367, 367, 367, 368, 368, 368, 368, 369, 369, 369, 369, 370, 370, 370, 370, 371, 371, 371, 371, 372, 372, 372, 372, 373, 373, 373, 373, 374, 374, 374, 374, 375, 375, 375, 375, 376, 376, 376, 376, 377, 377, 377, 377, 378, 378, 378, 378, 379, 379, 379, 379, 380, 380, 380, 380, 381, 381, 381, 381, 382, 382, 382, 382, 383, 383, 383, 383, 384, 384, 384, 384, 385, 385, 385, 385, 386, 386, 386, 386, 387, 387, 387, 387, 388, 388, 388, 388, 389, 389, 389, 389, 390, 390, 390, 390, 391, 391, 391, 391, 392, 392, 392, 392, 393, 393, 393, 393, 394, 394, 394, 394, 395, 395, 395, 395, 396, 396, 396, 396, 397, 397, 397, 397, 398, 398, 398, 398, 399, 399, 399, 399] ( + interpolation = "faceVarying" + ) + int primvars:ptexFaceOffset = 706 ( + interpolation = "constant" + ) + float[] primvars:u_map1 = [0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001] ( + interpolation = "faceVarying" + ) + float[] primvars:v_map1 = [1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7] ( + interpolation = "faceVarying" + ) + } + } + + over "Sim" ( + active = false + ) + { + } + variantSet "modelingVariant" = { + "ALL_VARIANTS" { + + } + "Cone" { + over "Geom" + { + over "pCube1" ( + active = false + ) + { + } + + over "pCylinder1" ( + active = false + ) + { + } + + over "pSphere1" ( + active = false + ) + { + } + + over "pTorus1" ( + active = false + ) + { + } + } + + } + "Cube" { + over "Geom" + { + over "pCone1" ( + active = false + ) + { + } + + over "pCylinder1" ( + active = false + ) + { + } + + over "pSphere1" ( + active = false + ) + { + } + + over "pTorus1" ( + active = false + ) + { + } + } + + } + "Cylinder" { + over "Geom" + { + over "pCone1" ( + active = false + ) + { + } + + over "pCube1" ( + active = false + ) + { + } + + over "pSphere1" ( + active = false + ) + { + } + + over "pTorus1" ( + active = false + ) + { + } + } + + } + "Sphere" { + over "Geom" + { + over "pCone1" ( + active = false + ) + { + } + + over "pCube1" ( + active = false + ) + { + } + + over "pCylinder1" ( + active = false + ) + { + } + + over "pTorus1" ( + active = false + ) + { + } + } + + } + "Torus" { + over "Geom" + { + over "pCone1" ( + active = false + ) + { + } + + over "pCube1" ( + active = false + ) + { + } + + over "pCylinder1" ( + active = false + ) + { + } + + over "pSphere1" ( + active = false + ) + { + } + } + + } + } +} + diff --git a/testsuite/test_0000/data/test.ass b/testsuite/test_0000/data/test.ass new file mode 100755 index 0000000000..e1fcabd1e3 --- /dev/null +++ b/testsuite/test_0000/data/test.ass @@ -0,0 +1,102 @@ +### exported: Mon Dec 17 21:54:24 2018 +### from: Arnold 5.2.2.0 [30b8ba14] windows icc-17.0.2 oiio-2.0.1 osl-1.10.1 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 2018/12/04 22:02:04 +### host app: MtoA 3.1.3.wip 7d48f6c4 (develop) Maya 2018 +### bounds: -1 -8.268288 -1 1 -6.268287 1 +### user: blaines +### render_layer: defaultRenderLayer +### scene: D:/arnold/scenes/usd.ma + + + +options +{ + AA_samples 1 + outputs "RGBA RGBA myfilter mydriver" + xres 160 + yres 120 + pixel_aspect_ratio 1.33333325 + camera "perspShape" + frame 1 +} + +gaussian_filter +{ + name myfilter +} + +driver_tiff +{ + name mydriver + filename "testrender.tif" + color_space "sRGB" +} + +persp_camera +{ + name perspShape + matrix + 0.716910601 2.77555756e-17 -0.697165132 0 + -0.320169091 0.888310015 -0.329237103 0 + 0.619298756 0.459244281 0.636838853 0 + 2.41154099 -5.45881033 2.70130825 1 + near_clip 0.100000001 + far_clip 10000 + screen_window_min -1 -1 + screen_window_max 1 1 + shutter_start 0 + shutter_end 0 + shutter_type "box" + rolling_shutter "off" + rolling_shutter_duration 0 + motion_start 0 + motion_end 0 + exposure 0 + fov 54.4322243 + uv_remap 0 0 0 1 + declare maya_full_name constant STRING + maya_full_name "|persp|perspShape" +} + +distant_light +{ + name directionalLightShape1 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 0 0 1 + exposure 0 + cast_shadows on + cast_volumetric_shadows on + shadow_density 1 + samples 1 + normalize on + diffuse 1 + specular 1 + sss 1 + indirect 1 + max_bounces 999 + volume_samples 2 + volume 1 + aov "default" + angle 0 + declare maya_full_name constant STRING + maya_full_name "|directionalLight1|directionalLightShape1" +} + +usd +{ + name aiUsdShape2 + visibility 255 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 -7.26828718 0 1 + use_light_group off + override_nodes off + filename "sphere.usd" + declare maya_full_name constant STRING + maya_full_name "|aiUsd2|aiUsdShape2" +} + diff --git a/testsuite/test_0000/ref/reference.log b/testsuite/test_0000/ref/reference.log new file mode 100755 index 0000000000..6ac3d1a255 --- /dev/null +++ b/testsuite/test_0000/ref/reference.log @@ -0,0 +1,210 @@ +00:00:02 60MB | log started Tue Dec 18 00:06:20 2018 +00:00:02 60MB | Arnold 5.2.2.0 [62163448] windows icc-17.0.2 oiio-2.0.1 osl-1.10.1 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 2018/12/04 03:55:51 +00:00:02 60MB | running on REM8WCK8D2, pid=13236 +00:00:02 60MB | 2 x Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz (20 cores, 40 logical) with 65458MB +00:00:02 60MB | Nvidia driver version 391.03 +00:00:02 60MB | GPU 0: Quadro K620 @ 1124MHz (compute 5.0) with 2048MB (1445MB available) +00:00:02 60MB | Windows 7 Enterprise Edition Service Pack 1 (version 6.1, build 7601) +00:00:02 60MB | soft limit for open files raised from 512 to 2048 +00:00:02 60MB | +00:00:02 60MB | loading plugins from C:\solidangle\mtoadeploy\2018\procedurals ... +00:00:02 60MB | mtoa_ParticleInstancer_proc.dll: particleInstancer uses Arnold 5.2.2.0 +00:00:02 60MB | mtoa_ParticleVolume_proc.dll: volume_particle uses Arnold 5.2.2.0 +00:00:02 60MB | mtoa_ParticleVolume_proc.dll: implicit_particle uses Arnold 5.2.2.0 +00:00:02 60MB | usd_proc.dll: usd uses Arnold 5.2.2.0 +00:00:02 60MB | [metadata] loading metadata file: C:\solidangle\mtoadeploy\2018\procedurals\usd_proc.mtd +00:00:02 60MB WARNING | unable to load dynamic library C:\solidangle\mtoadeploy\2018\procedurals\xgenSpline_procedural.dll: The specified module could not be found. + + +00:00:02 60MB WARNING | unable to load dynamic library C:\solidangle\mtoadeploy\2018\procedurals\xgen_procedural.dll: The specified module could not be found. + + +00:00:02 60MB | loaded 4 plugins from 3 lib(s) in 0:01.93 +00:00:02 60MB | loading plugins from D:\arnold\releases\Arnold_latest-windows\bin\..\plugins ... +00:00:02 60MB | alembic_proc.dll: alembic uses Arnold 5.2.2.0 +00:00:02 60MB | cryptomatte.dll: cryptomatte uses Arnold 5.2.2.0 +00:00:02 60MB | cryptomatte.dll: cryptomatte_filter uses Arnold 5.2.2.0 +00:00:02 60MB | cryptomatte.dll: cryptomatte_manifest_driver uses Arnold 5.2.2.0 +00:00:02 60MB | loaded 4 plugins from 2 lib(s) in 0:00.00 +00:00:02 60MB | [kick] command: D:\arnold\releases\Arnold_latest-windows\bin\kick test.ass -dw -r 160 120 -bs 16 -o testrender.tif -set driver_tiff.dither false -nocrashpopup -dp -v 6 -l C:\solidangle\mtoadeploy\2018\procedurals +00:00:02 60MB | loading plugins from C:\solidangle\mtoadeploy\2018\procedurals ... +00:00:02 60MB WARNING | unable to load dynamic library C:\solidangle\mtoadeploy\2018\procedurals\xgenSpline_procedural.dll: The specified module could not be found. + + +00:00:02 60MB WARNING | unable to load dynamic library C:\solidangle\mtoadeploy\2018\procedurals\xgen_procedural.dll: The specified module could not be found. + + +00:00:02 60MB | no plugins loaded +00:00:02 60MB | loading plugins from . ... +00:00:02 60MB | no plugins loaded +00:00:02 60MB | [metadata] loading metadata file: test.ass +00:00:02 61MB | [ass] loading test.ass ... +00:00:02 61MB | [ass] read 1817 bytes, 6 nodes in 0:00.00 +00:00:02 61MB | [kick] applying 1 attr value override +00:00:02 61MB | +00:00:02 61MB | authorizing with default license managers: rlm, clm ... +00:00:04 69MB | [clm] authorized for "86985ARNOL_2018_0F" in 0:01.75 +00:00:04 69MB | [clm] expiration date: permanent, in use: 2/100 +00:00:04 69MB | +00:00:04 69MB | [color_manager] no color manager is active +00:00:04 69MB | [color_manager] rendering color space is "linear" with declared chromaticities: +00:00:04 69MB | r(0.6400, 0.3300) g(0.3000, 0.6000) b(0.1500, 0.0600) and w(0.3127, 0.3290) +00:00:04 80MB | +00:00:04 80MB | there are 1 light and 2 objects: +00:00:04 80MB | 1 persp_camera +00:00:04 80MB | 1 distant_light +00:00:04 80MB | 1 utility +00:00:04 80MB | 1 driver_tiff +00:00:04 80MB | 1 gaussian_filter +00:00:04 80MB | 1 list_aggregate +00:00:04 80MB | 1 usd +00:00:04 80MB | +00:00:04 80MB | rendering image at 160 x 120, 1 AA sample +00:00:04 80MB | AA samples max +00:00:04 80MB | AA sample clamp +00:00:04 80MB | diffuse +00:00:04 80MB | specular +00:00:04 80MB | transmission samples 2 / depth 2 +00:00:04 80MB | volume indirect +00:00:04 80MB | total depth 10 +00:00:04 80MB | bssrdf samples 2 +00:00:04 80MB | transparency depth 10 +00:00:04 80MB | initializing 8 nodes ... +00:00:04 93MB | [proc] aiUsdShape2: loaded 1 nodes (1 objects, 0 shaders) +00:00:04 93MB | creating root object list ... +00:00:04 93MB | node initialization done in 0:00.04 (multithreaded) +00:00:04 93MB | updating 10 nodes ... +00:00:04 93MB | directionalLightShape1: distant_light using 1 sample, 2 volume samples +00:00:04 93MB | scene bounds: (-1 -8.26828766 -1) -> (1 -6.26828718 1) +00:00:04 93MB | node update done in 0:00.00 (multithreaded) +00:00:04 93MB | [aov] parsing 1 output statements ... +00:00:04 94MB | [aov] registered driver: "mydriver" (driver_tiff) +00:00:04 94MB | [aov] * "RGBA" of type RGBA filtered by "myfilter" (gaussian_filter) +00:00:04 94MB | [aov] done preparing 2 AOVs for 1 output to 1 driver (0 deep AOVs) +00:00:04 94MB | starting 40 bucket workers of size 16x16 ... +00:00:04 98MB | 0% done - 1 rays/pixel +00:00:04 99MB | [subdiv] /ExampleModelingVariants/Geom/pSphere1: regular subdivision done - 1 iterations: 400 faces => 1560 quads - 0:00.00 +00:00:04 100MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1560 prims, 1 key +00:00:04 100MB | 5% done - 1 rays/pixel +00:00:04 100MB | 10% done - 1 rays/pixel +00:00:04 100MB | 15% done - 1 rays/pixel +00:00:04 100MB | 20% done - 1 rays/pixel +00:00:04 100MB | 25% done - 1 rays/pixel +00:00:04 100MB | 30% done - 1 rays/pixel +00:00:04 100MB | 35% done - 1 rays/pixel +00:00:04 100MB | 40% done - 1 rays/pixel +00:00:04 100MB | 45% done - 1 rays/pixel +00:00:04 100MB | 50% done - 1 rays/pixel +00:00:04 100MB | 55% done - 1 rays/pixel +00:00:04 100MB | 60% done - 1 rays/pixel +00:00:04 100MB | 65% done - 2 rays/pixel +00:00:04 100MB | 70% done - 0 rays/pixel +00:00:04 100MB | 75% done - 0 rays/pixel +00:00:04 100MB | 80% done - 0 rays/pixel +00:00:04 100MB | 85% done - 0 rays/pixel +00:00:04 101MB | 90% done - 0 rays/pixel +00:00:04 101MB | 95% done - 0 rays/pixel +00:00:04 101MB | 100% done - 0 rays/pixel +00:00:04 101MB | render done in 0:00.011 +00:00:04 101MB | [driver_tiff] writing file `testrender.tif' +00:00:04 101MB | render done +00:00:04 101MB | +00:00:04 101MB | ----------------------------------------------------------------------------------- +00:00:04 101MB | scene creation time 0:02.33 machine utilization (0.00%) +00:00:04 101MB | plugin loading 0:02.21 +00:00:04 101MB | unaccounted 0:00.12 +00:00:04 101MB | ----------------------------------------------------------------------------------- +00:00:04 101MB | frame time 0:01.84 machine utilization (0.06%) +00:00:04 101MB | node init 0:00.04 +00:00:04 101MB | driver init/close 0:00.01 +00:00:04 101MB | rendering 0:00.01 +00:00:04 101MB | unaccounted 0:01.77 +00:00:04 101MB | ----------------------------------------------------------------------------------- +00:00:04 101MB | top session self-times by category +00:00:04 101MB | worker waiting 0:04.04 (98.31%) +00:00:04 101MB | Plugin loader 0:00.05 ( 1.34%) +00:00:04 101MB | thread blocked 0:00.01 ( 0.27%) +00:00:04 101MB | node_init (aiUsdShape2) 0:00.00 ( 0.03%) +00:00:04 101MB | initializeAllNodes 0:00.00 ( 0.03%) +00:00:04 101MB | TraceCameraRay 0:00.00 ( 0.01%) +00:00:04 101MB | ----------------------------------------------------------------------------------- +00:00:04 101MB | top session self-times by node +00:00:04 101MB | worker waiting 0:04.04 (98.31%) +00:00:04 101MB | Plugin loader 0:00.05 ( 1.34%) +00:00:04 101MB | polymesh:/ExampleModelingVariants/Geom/pSphere1 0:00.00 ( 0.15%) +00:00:04 101MB | thread blocked 0:00.00 ( 0.12%) +00:00:04 101MB | usd:aiUsdShape2 (node_init) 0:00.00 ( 0.03%) +00:00:04 101MB | initializeAllNodes 0:00.00 ( 0.03%) +00:00:04 101MB | ----------------------------------------------------------------------------------- +00:00:04 101MB | peak CPU memory used 101.25MB +00:00:04 101MB | at startup 36.41MB +00:00:04 101MB | plugins 7.86MB +00:00:04 101MB | AOV samples 0.42MB +00:00:04 101MB | output buffers 1.08MB +00:00:04 101MB | node overhead 0.00MB +00:00:04 101MB | message passing 0.08MB +00:00:04 101MB | memory pools 30.05MB +00:00:04 101MB | geometry 0.13MB +00:00:04 101MB | subdivs 0.13MB +00:00:04 101MB | accel. structs 0.05MB +00:00:04 101MB | strings 12.00MB +00:00:04 101MB | profiler 0.01MB +00:00:04 101MB | unaccounted 13.16MB +00:00:04 101MB | ----------------------------------------------------------------------------------- +00:00:04 101MB | ray counts ( /pixel, /sample) (% total) (avg. hits) (max hits) +00:00:04 101MB | camera 24160 ( 1.26, 1.00) (100.00%) ( 0.33) ( 1) +00:00:04 101MB | total 24160 ( 1.26, 1.00) (100.00%) ( 0.33) ( 1) +00:00:04 101MB | by ray depth: 0 +00:00:04 101MB | total 100.0% +00:00:04 101MB | ----------------------------------------------------------------------------------- +00:00:04 101MB | shader calls ( /pixel, /sample) (% total) +00:00:04 101MB | primary 7933 ( 0.41, 0.33) (100.00%) +00:00:04 101MB | total 7933 ( 0.41, 0.33) (100.00%) +00:00:04 101MB | by ray depth: 0 +00:00:04 101MB | total 100.0% +00:00:04 101MB | ----------------------------------------------------------------------------------- +00:00:04 101MB | geometry (% hit ) (instances) ( init mem, final mem) +00:00:04 101MB | lists 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:04 101MB | procs 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:04 101MB | subdivs 1 (100.0%) ( 0) ( 0.04, 0.13) +00:00:04 101MB | ----------------------------------------------------------------------------------- +00:00:04 101MB | geometric elements ( min) ( avg.) ( max) +00:00:04 101MB | objects (procs) 1 ( 1) ( 1.0) ( 1) +00:00:04 101MB | subdiv patches 400 ( 400) ( 400.0) ( 400) +00:00:04 101MB | ----------------------------------------------------------------------------------- +00:00:04 101MB | triangle tessellation ( min) ( avg.) ( max) (/ element) (% total) +00:00:04 101MB | subdivs 3120 ( 3120) ( 3120.0) ( 3120) ( 7.80) (100.00%) +00:00:04 101MB | iterations 1 3120 ( 3120) ( 3120.0) ( 3120) ( 7.80) (100.00%) +00:00:04 101MB | unique triangles 3120 +00:00:04 101MB | CPU memory use 0.13MB +00:00:04 101MB | vertices 0.02MB +00:00:04 101MB | vertex indices 0.01MB +00:00:04 101MB | packed normals 0.01MB +00:00:04 101MB | normal indices 0.00MB +00:00:04 101MB | uniform indices 0.00MB +00:00:04 101MB | userdata 0.10MB +00:00:04 101MB | largest polymeshes by triangle count +00:00:04 101MB | 3120 tris -- /ExampleModelingVariants/Geom/pSphere1 +00:00:04 101MB | ----------------------------------------------------------------------------------- +00:00:04 101MB | acceleration structures: (% total) +00:00:04 101MB | list 2 ( 66.67%) +00:00:04 101MB | bvh 1 ( 33.33%) +00:00:04 101MB | total 3 (100.00%) +00:00:04 101MB | ----------------------------------------------------------------------------------- +00:00:04 101MB | number of warnings, warning type: +00:00:04 101MB | 4: unable to load dynamic library %s: %s +00:00:04 101MB | ----------------------------------------------------------------------------------- +00:00:04 101MB | performance warnings: +00:00:04 101MB WARNING | Rendering utilization was only 0%. Your render may be bound by a single threaded process or I/O. +00:00:04 101MB WARNING | Scene creation was a significant amount of total time (56%). Consider optimizing this process first. +00:00:04 101MB | ----------------------------------------------------------------------------------- +00:00:04 98MB | +00:00:04 98MB | releasing resources +00:00:04 85MB | unloading 5 plugins +00:00:04 85MB | closing mtoa_ParticleInstancer_proc.dll ... +00:00:04 85MB | closing mtoa_ParticleVolume_proc.dll ... +00:00:04 85MB | closing usd_proc.dll ... +00:00:04 84MB | closing alembic_proc.dll ... +00:00:04 84MB | closing cryptomatte.dll ... +00:00:04 84MB | unloading plugins done +00:00:04 84MB | Arnold shutdown diff --git a/testsuite/test_0000/ref/reference.tif b/testsuite/test_0000/ref/reference.tif new file mode 100755 index 0000000000..2dc8babac4 Binary files /dev/null and b/testsuite/test_0000/ref/reference.tif differ diff --git a/testsuite/test_0001/README b/testsuite/test_0001/README new file mode 100755 index 0000000000..b1efe1b46d --- /dev/null +++ b/testsuite/test_0001/README @@ -0,0 +1,4 @@ +Test Points + +author: sebastien ortega + diff --git a/testsuite/test_0001/data/Particles_Splash.101.usd b/testsuite/test_0001/data/Particles_Splash.101.usd new file mode 100755 index 0000000000..3e42dab5ee --- /dev/null +++ b/testsuite/test_0001/data/Particles_Splash.101.usd @@ -0,0 +1,47 @@ +#usda 1.0 +( + endTimeCode = 101 + startTimeCode = 101 +) + +def Xform "World" ( + customData = { + bool zUp = 1 + } + kind = "group" +) +{ + def Xform "fx" ( + kind = "group" + ) + { + def Xform "Particles_Splash" ( + kind = "component" + ) + { + def Points "points" + { + Vec3f[] extent.timeSamples = { + 101: [(-81.62381, -112.74623, -0.76687664), (-78.21893, -110.6951, 0.18761282)], + } + PointFloat[] points.timeSamples = { + 101: [(-2, 0, 0), (2, 0, 0), (0, 2, 0), (0, -2, 0),(0, 0, -2),(0, 0, 2)], + } + custom int[] primvars:id ( + elementSize = 1 + interpolation = "varying" + ) + + float[] widths.timeSamples = { + 101: [0.55111823, 0.569182776, 0.38235222, 0.456548156, 0.49467373, 0.49127388], + } + custom Matrix4d xformOp:transform + Matrix4d xformOp:transform.timeSamples = { + 101: ( (1.5, 0, 0, 0), (0, 1.5, 0, 0), (0, 0, 1.5, 0), (0, 0, 0, 1.5) ), + } + uniform token[] xformOpOrder = ["xformOp:transform"] + } + } + } +} + diff --git a/testsuite/test_0001/data/test.ass b/testsuite/test_0001/data/test.ass new file mode 100755 index 0000000000..f167a049db --- /dev/null +++ b/testsuite/test_0001/data/test.ass @@ -0,0 +1,80 @@ +### exported: Mon Dec 17 21:54:24 2018 +### from: Arnold 5.2.2.0 [30b8ba14] windows icc-17.0.2 oiio-2.0.1 osl-1.10.1 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 2018/12/04 22:02:04 +### host app: MtoA 3.1.3.wip 7d48f6c4 (develop) Maya 2018 +### bounds: -1 -8.268288 -1 1 -6.268287 1 +### user: blaines +### render_layer: defaultRenderLayer +### scene: D:/arnold/scenes/usd.ma + + + +options +{ + AA_samples 1 + outputs "RGBA RGBA myfilter mydriver" + xres 160 + yres 120 + pixel_aspect_ratio 1.33333325 + camera "perspShape" + frame 1 +} + +gaussian_filter +{ + name myfilter +} + +driver_tiff +{ + name mydriver + filename "testrender.tif" + color_space "sRGB" +} + +persp_camera +{ + name perspShape + matrix + 0.716910601 2.77555756e-17 -0.697165132 0 + -0.320169091 0.888310015 -0.329237103 0 + 0.619298756 0.459244281 0.636838853 0 + 2.41154099 -5.45881033 2.70130825 1 + near_clip 0.100000001 + far_clip 10000 + screen_window_min -1 -1 + screen_window_max 1 1 + shutter_start 0 + shutter_end 0 + shutter_type "box" + rolling_shutter "off" + rolling_shutter_duration 0 + motion_start 0 + motion_end 0 + exposure 0 + fov 124.4322243 + uv_remap 0 0 0 1 + declare maya_full_name constant STRING + maya_full_name "|persp|perspShape" +} +skydome_light +{ + name dome + camera 0.1 +} +usd +{ + name aiUsdShape2 + visibility 255 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 -7.26828718 0 1 + frame 101 + use_light_group off + override_nodes off + filename "Particles_Splash.101.usd" + declare maya_full_name constant STRING + maya_full_name "|aiUsd2|aiUsdShape2" +} + diff --git a/testsuite/test_0001/ref/reference.log b/testsuite/test_0001/ref/reference.log new file mode 100755 index 0000000000..12af3d7983 --- /dev/null +++ b/testsuite/test_0001/ref/reference.log @@ -0,0 +1,193 @@ +00:00:01 60MB | log started Tue Dec 18 07:59:43 2018 +00:00:01 60MB | Arnold 5.2.2.0 [62163448] windows icc-17.0.2 oiio-2.0.1 osl-1.10.1 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 2018/12/04 03:55:51 +00:00:01 60MB | running on REM8WCK8D2, pid=3404 +00:00:01 60MB | 2 x Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz (20 cores, 40 logical) with 65458MB +00:00:01 60MB | Nvidia driver version 391.03 +00:00:01 60MB | GPU 0: Quadro K620 @ 1124MHz (compute 5.0) with 2048MB (1519MB available) +00:00:01 60MB | Windows 7 Enterprise Edition Service Pack 1 (version 6.1, build 7601) +00:00:01 60MB | soft limit for open files raised from 512 to 2048 +00:00:01 60MB | +00:00:01 60MB | loading plugins from C:\solidangle\mtoadeploy\2018\procedurals ... +00:00:01 60MB | mtoa_ParticleInstancer_proc.dll: particleInstancer uses Arnold 5.2.2.0 +00:00:01 60MB | mtoa_ParticleVolume_proc.dll: volume_particle uses Arnold 5.2.2.0 +00:00:01 60MB | mtoa_ParticleVolume_proc.dll: implicit_particle uses Arnold 5.2.2.0 +00:00:01 60MB | usd_proc.dll: usd uses Arnold 5.2.2.0 +00:00:01 60MB | [metadata] loading metadata file: C:\solidangle\mtoadeploy\2018\procedurals\usd_proc.mtd +00:00:01 60MB WARNING | unable to load dynamic library C:\solidangle\mtoadeploy\2018\procedurals\xgenSpline_procedural.dll: The specified module could not be found. + + +00:00:01 60MB WARNING | unable to load dynamic library C:\solidangle\mtoadeploy\2018\procedurals\xgen_procedural.dll: The specified module could not be found. + + +00:00:01 60MB | loaded 4 plugins from 3 lib(s) in 0:01.80 +00:00:01 60MB | loading plugins from D:\arnold\releases\Arnold_latest-windows\bin\..\plugins ... +00:00:01 60MB | alembic_proc.dll: alembic uses Arnold 5.2.2.0 +00:00:01 60MB | cryptomatte.dll: cryptomatte uses Arnold 5.2.2.0 +00:00:01 60MB | cryptomatte.dll: cryptomatte_filter uses Arnold 5.2.2.0 +00:00:01 60MB | cryptomatte.dll: cryptomatte_manifest_driver uses Arnold 5.2.2.0 +00:00:01 60MB | loaded 4 plugins from 2 lib(s) in 0:00.00 +00:00:01 60MB | [kick] command: D:\arnold\releases\Arnold_latest-windows\bin\kick test.ass -dw -r 160 120 -bs 16 -o testrender.tif -set driver_tiff.dither false -nocrashpopup -dp -v 6 -l C:\solidangle\mtoadeploy\2018\procedurals +00:00:01 60MB | loading plugins from C:\solidangle\mtoadeploy\2018\procedurals ... +00:00:02 60MB WARNING | unable to load dynamic library C:\solidangle\mtoadeploy\2018\procedurals\xgenSpline_procedural.dll: The specified module could not be found. + + +00:00:02 60MB WARNING | unable to load dynamic library C:\solidangle\mtoadeploy\2018\procedurals\xgen_procedural.dll: The specified module could not be found. + + +00:00:02 60MB | no plugins loaded +00:00:02 60MB | loading plugins from . ... +00:00:02 60MB | no plugins loaded +00:00:02 60MB | [metadata] loading metadata file: test.ass +00:00:02 61MB | [ass] loading test.ass ... +00:00:02 61MB | [ass] read 1480 bytes, 6 nodes in 0:00.00 +00:00:02 61MB | [kick] applying 1 attr value override +00:00:02 61MB | +00:00:02 61MB | authorizing with default license managers: rlm, clm ... +00:00:03 69MB | [clm] authorized for "86985ARNOL_2018_0F" in 0:01.16 +00:00:03 69MB | [clm] expiration date: permanent, in use: 2/100 +00:00:03 69MB | +00:00:03 69MB | [color_manager] no color manager is active +00:00:03 69MB | [color_manager] rendering color space is "linear" with declared chromaticities: +00:00:03 69MB | r(0.6400, 0.3300) g(0.3000, 0.6000) b(0.1500, 0.0600) and w(0.3127, 0.3290) +00:00:03 80MB | +00:00:03 80MB | there are 1 light and 2 objects: +00:00:03 80MB | 1 persp_camera +00:00:03 80MB | 1 skydome_light +00:00:03 80MB | 1 utility +00:00:03 80MB | 1 driver_tiff +00:00:03 80MB | 1 gaussian_filter +00:00:03 80MB | 1 list_aggregate +00:00:03 80MB | 1 usd +00:00:03 80MB | +00:00:03 80MB | rendering image at 160 x 120, 1 AA sample +00:00:03 80MB | AA samples max +00:00:03 80MB | AA sample clamp +00:00:03 80MB | diffuse +00:00:03 80MB | specular +00:00:03 80MB | transmission samples 2 / depth 2 +00:00:03 80MB | volume indirect +00:00:03 80MB | total depth 10 +00:00:03 80MB | bssrdf samples 2 +00:00:03 80MB | transparency depth 10 +00:00:03 80MB | initializing 8 nodes ... +00:00:03 93MB | [proc] aiUsdShape2: loaded 1 nodes (1 objects, 0 shaders) +00:00:03 93MB | creating root object list ... +00:00:03 93MB | node initialization done in 0:00.13 (multithreaded) +00:00:03 93MB | updating 10 nodes ... +00:00:03 93MB | dome: skydome_light using 1 sample, 2 volume samples +00:00:03 93MB | scene bounds: (-3.82667756 -10.9531097 -3.74201059) -> (3.85377431 -3.69475865 3.73691082) +00:00:03 93MB | node update done in 0:00.00 (multithreaded) +00:00:03 93MB | [aov] parsing 1 output statements ... +00:00:03 93MB | [aov] registered driver: "mydriver" (driver_tiff) +00:00:03 93MB | [aov] * "RGBA" of type RGBA filtered by "myfilter" (gaussian_filter) +00:00:03 93MB | [aov] done preparing 2 AOVs for 1 output to 1 driver (0 deep AOVs) +00:00:03 94MB | starting 40 bucket workers of size 16x16 ... +00:00:03 101MB | [accel] points bvh4 done - 0:00.00 (wall time) - 6 prims, 1 key +00:00:03 101MB | 0% done - 1 rays/pixel +00:00:03 101MB | 5% done - 1 rays/pixel +00:00:03 101MB | 10% done - 1 rays/pixel +00:00:03 101MB | 15% done - 1 rays/pixel +00:00:03 101MB | 20% done - 1 rays/pixel +00:00:03 101MB | 25% done - 1 rays/pixel +00:00:03 101MB | 30% done - 1 rays/pixel +00:00:03 101MB | 35% done - 1 rays/pixel +00:00:03 102MB | 40% done - 1 rays/pixel +00:00:03 102MB | 45% done - 1 rays/pixel +00:00:03 102MB | 50% done - 1 rays/pixel +00:00:03 102MB | 55% done - 1 rays/pixel +00:00:03 102MB | 60% done - 1 rays/pixel +00:00:03 102MB | 65% done - 1 rays/pixel +00:00:03 102MB | 70% done - 0 rays/pixel +00:00:03 102MB | 75% done - 0 rays/pixel +00:00:03 102MB | 80% done - 0 rays/pixel +00:00:03 102MB | 85% done - 0 rays/pixel +00:00:03 102MB | 90% done - 0 rays/pixel +00:00:03 102MB | 95% done - 0 rays/pixel +00:00:03 102MB | 100% done - 0 rays/pixel +00:00:03 102MB | render done in 0:00.005 +00:00:03 102MB | [driver_tiff] writing file `testrender.tif' +00:00:03 102MB | render done +00:00:03 102MB | +00:00:03 102MB | ----------------------------------------------------------------------------------- +00:00:03 102MB | scene creation time 0:02.52 machine utilization (0.03%) +00:00:03 102MB | plugin loading 0:02.40 +00:00:03 102MB | unaccounted 0:00.11 +00:00:03 102MB | ----------------------------------------------------------------------------------- +00:00:03 102MB | frame time 0:01.34 machine utilization (4.64%) +00:00:03 102MB | node init 0:00.13 +00:00:03 102MB | unaccounted 0:01.19 +00:00:03 102MB | ----------------------------------------------------------------------------------- +00:00:03 102MB | top session self-times by category +00:00:03 102MB | worker waiting 0:03.68 (98.13%) +00:00:03 102MB | Plugin loader 0:00.06 ( 1.60%) +00:00:03 102MB | initializeAllNodes 0:00.00 ( 0.09%) +00:00:03 102MB | node_init (aiUsdShape2) 0:00.00 ( 0.09%) +00:00:03 102MB | thread blocked 0:00.00 ( 0.06%) +00:00:03 102MB | driver_close (mydriver) 0:00.00 ( 0.01%) +00:00:03 102MB | ----------------------------------------------------------------------------------- +00:00:03 102MB | top session self-times by node +00:00:03 102MB | worker waiting 0:03.68 (98.13%) +00:00:03 102MB | Plugin loader 0:00.06 ( 1.60%) +00:00:03 102MB | initializeAllNodes 0:00.00 ( 0.09%) +00:00:03 102MB | usd:aiUsdShape2 (node_init) 0:00.00 ( 0.09%) +00:00:03 102MB | thread blocked 0:00.00 ( 0.06%) +00:00:03 102MB | driver_tiff:mydriver (driver_close) 0:00.00 ( 0.01%) +00:00:03 102MB | ----------------------------------------------------------------------------------- +00:00:03 102MB | peak CPU memory used 102.64MB +00:00:03 102MB | at startup 36.41MB +00:00:03 102MB | plugins 7.95MB +00:00:03 102MB | AOV samples 0.42MB +00:00:03 102MB | output buffers 1.08MB +00:00:03 102MB | node overhead 0.00MB +00:00:03 102MB | message passing 0.08MB +00:00:03 102MB | memory pools 30.05MB +00:00:03 102MB | geometry 0.00MB +00:00:03 102MB | points 0.00MB +00:00:03 102MB | accel. structs 0.00MB +00:00:03 102MB | strings 12.00MB +00:00:03 102MB | profiler 0.00MB +00:00:03 102MB | unaccounted 14.64MB +00:00:03 102MB | ----------------------------------------------------------------------------------- +00:00:03 102MB | ray counts ( /pixel, /sample) (% total) (avg. hits) (max hits) +00:00:03 102MB | camera 24160 ( 1.26, 1.00) (100.00%) ( 0.21) ( 1) +00:00:03 102MB | total 24160 ( 1.26, 1.00) (100.00%) ( 0.21) ( 1) +00:00:03 102MB | by ray depth: 0 +00:00:03 102MB | total 100.0% +00:00:03 102MB | ----------------------------------------------------------------------------------- +00:00:03 102MB | shader calls ( /pixel, /sample) (% total) +00:00:03 102MB | primary 5019 ( 0.26, 0.21) (100.00%) +00:00:03 102MB | total 5019 ( 0.26, 0.21) (100.00%) +00:00:03 102MB | by ray depth: 0 +00:00:03 102MB | total 100.0% +00:00:03 102MB | ----------------------------------------------------------------------------------- +00:00:03 102MB | geometry (% hit ) (instances) ( init mem, final mem) +00:00:03 102MB | lists 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:03 102MB | procs 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:03 102MB | points 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:03 102MB | ----------------------------------------------------------------------------------- +00:00:03 102MB | geometric elements ( min) ( avg.) ( max) +00:00:03 102MB | objects (procs) 1 ( 1) ( 1.0) ( 1) +00:00:03 102MB | points 6 ( 6) ( 6.0) ( 6) +00:00:03 102MB | ----------------------------------------------------------------------------------- +00:00:03 102MB | acceleration structures: (% total) +00:00:03 102MB | list 2 ( 66.67%) +00:00:03 102MB | bvh 1 ( 33.33%) +00:00:03 102MB | total 3 (100.00%) +00:00:03 102MB | ----------------------------------------------------------------------------------- +00:00:03 102MB | number of warnings, warning type: +00:00:03 102MB | 4: unable to load dynamic library %s: %s +00:00:03 102MB | ----------------------------------------------------------------------------------- +00:00:03 102MB | performance warnings: +00:00:03 102MB WARNING | Rendering utilization was only 5%. Your render may be bound by a single threaded process or I/O. +00:00:03 102MB WARNING | Scene creation was a significant amount of total time (65%). Consider optimizing this process first. +00:00:03 102MB | ----------------------------------------------------------------------------------- +00:00:03 98MB | +00:00:03 98MB | releasing resources +00:00:04 86MB | unloading 5 plugins +00:00:04 86MB | closing mtoa_ParticleInstancer_proc.dll ... +00:00:04 86MB | closing mtoa_ParticleVolume_proc.dll ... +00:00:04 86MB | closing usd_proc.dll ... +00:00:04 85MB | closing alembic_proc.dll ... +00:00:04 85MB | closing cryptomatte.dll ... +00:00:04 85MB | unloading plugins done +00:00:04 85MB | Arnold shutdown diff --git a/testsuite/test_0001/ref/reference.tif b/testsuite/test_0001/ref/reference.tif new file mode 100755 index 0000000000..fa7dc5148d Binary files /dev/null and b/testsuite/test_0001/ref/reference.tif differ diff --git a/testsuite/test_0002/README b/testsuite/test_0002/README new file mode 100755 index 0000000000..650c451b86 --- /dev/null +++ b/testsuite/test_0002/README @@ -0,0 +1,4 @@ +Test Builtin Shapes (cube, sphere, cone, cylinder, capsule) + +author: sebastien ortega + diff --git a/testsuite/test_0002/data/builtin_shapes.usda b/testsuite/test_0002/data/builtin_shapes.usda new file mode 100755 index 0000000000..ca0018e611 --- /dev/null +++ b/testsuite/test_0002/data/builtin_shapes.usda @@ -0,0 +1,43 @@ +#usda 1.0 +( + defaultPrim = "cube" +) + +def Cube "cube" +{ + double size=2 + float3 xformOp:translate= (4.8,0, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] +} +def Sphere "sphere" +{ + double radius=1.8 + float3 xformOp:translate= (-4.8,0, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] +} + +def Cylinder "cylinder" +{ + double radius=1.1 + double height=3 + token axis="Y" + float3 xformOp:translate= (0,0, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] +} + +def Cone "cone" +{ + double radius=1.6 + double height=2.7 + token axis="X" + float3 xformOp:translate= (0,5, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] +} +def Capsule "capsule" +{ + double radius=1.6 + double height=2.7 + token axis="X" + float3 xformOp:translate= (4,5, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] +} \ No newline at end of file diff --git a/testsuite/test_0002/data/test.ass b/testsuite/test_0002/data/test.ass new file mode 100755 index 0000000000..1f8ef73a34 --- /dev/null +++ b/testsuite/test_0002/data/test.ass @@ -0,0 +1,110 @@ +### exported: Tue Dec 18 15:45:58 2018 +### from: Arnold 5.2.2.0 [30b8ba14] windows icc-17.0.2 oiio-2.0.1 osl-1.10.1 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 2018/12/04 22:02:04 +### host app: MtoA 3.1.3.wip 7d48f6c4 (develop) Maya 2018 +### bounds: -1 -1 -1 1 1 1 +### user: blaines +### render_layer: defaultRenderLayer +### scene: D:/arnold/scenes/usd_builtin.ma + + + +options +{ + AA_samples 3 + AA_samples_max 8 + outputs "RGBA RGBA myfilter mydriver" + xres 960 + yres 540 + texture_per_file_stats on + texture_automip off + camera "perspShape" + frame 1 + GI_diffuse_depth 1 + GI_specular_depth 1 + GI_transmission_depth 8 + declare render_layer constant STRING + render_layer "defaultRenderLayer" +} + +gaussian_filter +{ + name myfilter +} + +driver_tiff +{ + name mydriver + filename "testrender.tif" + color_space "sRGB" +} + +persp_camera +{ + name perspShape + matrix + 0.99999392 -1.08420217e-19 0.00349065149 0 + 0.000781565788 0.974611521 -0.223901182 0 + -0.00340202916 0.223902553 0.97460562 0 + -0.949623287 7.26941013 21.0998859 1 + near_clip 0.100000001 + far_clip 10000 + screen_window_min -1 -1 + screen_window_max 1 1 + shutter_start 0 + shutter_end 0 + shutter_type "box" + rolling_shutter "off" + rolling_shutter_duration 0 + motion_start 0 + motion_end 0 + exposure 0 + fov 54.4322243 + uv_remap 0 0 0 1 + declare maya_full_name constant STRING + maya_full_name "|persp|perspShape" +} + +distant_light +{ + name directionalLightShape1 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 0 0 1 + exposure 0 + cast_shadows on + cast_volumetric_shadows on + shadow_density 1 + samples 1 + normalize on + diffuse 1 + specular 1 + sss 1 + indirect 1 + max_bounces 999 + volume_samples 2 + volume 1 + aov "default" + angle 0 + declare maya_full_name constant STRING + maya_full_name "|directionalLight1|directionalLightShape1" +} + +usd +{ + name aiUsdShape1 + visibility 255 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 0 0 1 + use_light_group off + override_nodes off + filename "builtin_shapes.usda" + frame 1 + declare maya_full_name constant STRING + maya_full_name "|aiUsd1|aiUsdShape1" +} + diff --git a/testsuite/test_0002/ref/reference.log b/testsuite/test_0002/ref/reference.log new file mode 100755 index 0000000000..659478af18 --- /dev/null +++ b/testsuite/test_0002/ref/reference.log @@ -0,0 +1,193 @@ +00:00:01 60MB | log started Tue Dec 18 15:48:57 2018 +00:00:01 60MB | Arnold 5.2.2.0 [62163448] windows icc-17.0.2 oiio-2.0.1 osl-1.10.1 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 2018/12/04 03:55:51 +00:00:01 60MB | running on REM8WCK8D2, pid=14484 +00:00:01 60MB | 2 x Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz (20 cores, 40 logical) with 65458MB +00:00:01 60MB | Nvidia driver version 391.03 +00:00:01 60MB | GPU 0: Quadro K620 @ 1124MHz (compute 5.0) with 2048MB (1334MB available) +00:00:01 60MB | Windows 7 Enterprise Edition Service Pack 1 (version 6.1, build 7601) +00:00:01 60MB | soft limit for open files raised from 512 to 2048 +00:00:01 60MB | +00:00:01 60MB | loading plugins from C:\solidangle\mtoadeploy\2018\procedurals ... +00:00:01 60MB | mtoa_ParticleInstancer_proc.dll: particleInstancer uses Arnold 5.2.2.0 +00:00:01 60MB | mtoa_ParticleVolume_proc.dll: volume_particle uses Arnold 5.2.2.0 +00:00:01 60MB | mtoa_ParticleVolume_proc.dll: implicit_particle uses Arnold 5.2.2.0 +00:00:01 60MB | usd_proc.dll: usd uses Arnold 5.2.2.0 +00:00:01 60MB | [metadata] loading metadata file: C:\solidangle\mtoadeploy\2018\procedurals\usd_proc.mtd +00:00:01 60MB WARNING | unable to load dynamic library C:\solidangle\mtoadeploy\2018\procedurals\xgenSpline_procedural.dll: The specified module could not be found. + + +00:00:01 60MB WARNING | unable to load dynamic library C:\solidangle\mtoadeploy\2018\procedurals\xgen_procedural.dll: The specified module could not be found. + + +00:00:01 60MB | loaded 4 plugins from 3 lib(s) in 0:01.71 +00:00:01 60MB | loading plugins from D:\arnold\releases\Arnold_latest-windows\bin\..\plugins ... +00:00:01 60MB | alembic_proc.dll: alembic uses Arnold 5.2.2.0 +00:00:01 60MB | cryptomatte.dll: cryptomatte uses Arnold 5.2.2.0 +00:00:01 60MB | cryptomatte.dll: cryptomatte_filter uses Arnold 5.2.2.0 +00:00:01 60MB | cryptomatte.dll: cryptomatte_manifest_driver uses Arnold 5.2.2.0 +00:00:01 60MB | loaded 4 plugins from 2 lib(s) in 0:00.00 +00:00:01 60MB | [kick] command: D:\arnold\releases\Arnold_latest-windows\bin\kick test.ass -dw -r 160 120 -bs 16 -o testrender.tif -set driver_tiff.dither false -nocrashpopup -dp -v 6 -l C:\solidangle\mtoadeploy\2018\procedurals +00:00:01 60MB | loading plugins from C:\solidangle\mtoadeploy\2018\procedurals ... +00:00:01 60MB WARNING | unable to load dynamic library C:\solidangle\mtoadeploy\2018\procedurals\xgenSpline_procedural.dll: The specified module could not be found. + + +00:00:02 60MB WARNING | unable to load dynamic library C:\solidangle\mtoadeploy\2018\procedurals\xgen_procedural.dll: The specified module could not be found. + + +00:00:02 60MB | no plugins loaded +00:00:02 60MB | loading plugins from . ... +00:00:02 60MB | no plugins loaded +00:00:02 60MB | [metadata] loading metadata file: test.ass +00:00:02 61MB | [ass] loading test.ass ... +00:00:02 61MB | [ass] read 1998 bytes, 6 nodes in 0:00.00 +00:00:02 61MB | [kick] applying 1 attr value override +00:00:02 61MB | +00:00:02 61MB | authorizing with default license managers: rlm, clm ... +00:00:04 69MB | [clm] authorized for "86985ARNOL_2018_0F" in 0:01.66 +00:00:04 69MB | [clm] expiration date: permanent, in use: 2/100 +00:00:04 69MB | +00:00:04 69MB | [color_manager] no color manager is active +00:00:04 69MB | [color_manager] rendering color space is "linear" with declared chromaticities: +00:00:04 69MB | r(0.6400, 0.3300) g(0.3000, 0.6000) b(0.1500, 0.0600) and w(0.3127, 0.3290) +00:00:04 80MB | +00:00:04 80MB | there are 1 light and 2 objects: +00:00:04 80MB | 1 persp_camera +00:00:04 80MB | 1 distant_light +00:00:04 80MB | 1 utility +00:00:04 80MB | 1 driver_tiff +00:00:04 80MB | 1 gaussian_filter +00:00:04 80MB | 1 list_aggregate +00:00:04 80MB | 1 usd +00:00:04 80MB | +00:00:04 80MB | rendering image at 160 x 120, 3 AA samples +00:00:04 80MB | AA samples max +00:00:04 80MB | AA sample clamp +00:00:04 80MB | diffuse samples 2 / depth 1 +00:00:04 80MB | specular samples 2 / depth 1 +00:00:04 80MB | transmission samples 2 / depth 8 +00:00:04 80MB | volume indirect +00:00:04 80MB | total depth 10 +00:00:04 80MB | bssrdf samples 2 +00:00:04 80MB | transparency depth 10 +00:00:04 80MB | initializing 8 nodes ... +00:00:04 93MB | [proc] aiUsdShape1: loaded 5 nodes (5 objects, 0 shaders) +00:00:04 93MB | creating root object list ... +00:00:04 93MB | node initialization done in 0:00.06 (multithreaded) +00:00:04 93MB | updating 14 nodes ... +00:00:04 93MB | directionalLightShape1: distant_light using 1 sample, 2 volume samples +00:00:04 93MB | scene bounds: (-6.60000038 -1.79999995 -1.79999995) -> (5.80000019 6.60000086 1.79999995) +00:00:04 93MB | node update done in 0:00.00 (multithreaded) +00:00:04 93MB | [aov] parsing 1 output statements ... +00:00:04 93MB | [aov] registered driver: "mydriver" (driver_tiff) +00:00:04 93MB | [aov] * "RGBA" of type RGBA filtered by "myfilter" (gaussian_filter) +00:00:04 93MB | [aov] done preparing 2 AOVs for 1 output to 1 driver (0 deep AOVs) +00:00:04 94MB | starting 40 bucket workers of size 16x16 ... +00:00:04 101MB | [accel] procedural bvh4 done - 0:00.00 (wall time) - 5 prims, 1 key +00:00:04 101MB | 0% done - 10 rays/pixel +00:00:04 101MB | 5% done - 10 rays/pixel +00:00:04 101MB | 10% done - 10 rays/pixel +00:00:04 101MB | 15% done - 10 rays/pixel +00:00:04 101MB | 20% done - 10 rays/pixel +00:00:04 101MB | 25% done - 10 rays/pixel +00:00:04 102MB | 30% done - 10 rays/pixel +00:00:04 102MB | 35% done - 10 rays/pixel +00:00:04 102MB | 40% done - 10 rays/pixel +00:00:04 102MB | 45% done - 10 rays/pixel +00:00:04 102MB | 50% done - 10 rays/pixel +00:00:04 102MB | 55% done - 10 rays/pixel +00:00:04 102MB | 60% done - 10 rays/pixel +00:00:04 102MB | 65% done - 10 rays/pixel +00:00:04 102MB | 70% done - 11 rays/pixel +00:00:04 102MB | 75% done - 0 rays/pixel +00:00:04 102MB | 80% done - 0 rays/pixel +00:00:04 102MB | 85% done - 0 rays/pixel +00:00:04 102MB | 90% done - 0 rays/pixel +00:00:04 102MB | 95% done - 0 rays/pixel +00:00:04 102MB | 100% done - 0 rays/pixel +00:00:04 102MB | render done in 0:00.015 +00:00:04 102MB | [driver_tiff] writing file `testrender.tif' +00:00:04 102MB | render done +00:00:04 102MB | +00:00:04 102MB | ----------------------------------------------------------------------------------- +00:00:04 102MB | scene creation time 0:02.53 machine utilization (0.02%) +00:00:04 102MB | plugin loading 0:02.41 +00:00:04 102MB | unaccounted 0:00.11 +00:00:04 102MB | ----------------------------------------------------------------------------------- +00:00:04 102MB | frame time 0:01.79 machine utilization (1.70%) +00:00:04 102MB | node init 0:00.06 +00:00:04 102MB | rendering 0:00.01 +00:00:04 102MB | pixel rendering 0:00.01 +00:00:04 102MB | unaccounted 0:01.69 +00:00:04 102MB | ----------------------------------------------------------------------------------- +00:00:04 102MB | top session self-times by category +00:00:04 102MB | worker waiting 0:04.16 (98.28%) +00:00:04 102MB | Plugin loader 0:00.06 ( 1.43%) +00:00:04 102MB | thread blocked 0:00.00 ( 0.08%) +00:00:04 102MB | node_init (aiUsdShape1) 0:00.00 ( 0.04%) +00:00:04 102MB | initializeAllNodes 0:00.00 ( 0.04%) +00:00:04 102MB | writeBucket 0:00.00 ( 0.04%) +00:00:04 102MB | ----------------------------------------------------------------------------------- +00:00:04 102MB | top session self-times by node +00:00:04 102MB | worker waiting 0:04.16 (98.28%) +00:00:04 102MB | Plugin loader 0:00.06 ( 1.43%) +00:00:04 102MB | usd:aiUsdShape1 0:00.00 ( 0.09%) +00:00:04 102MB | thread blocked 0:00.00 ( 0.07%) +00:00:04 102MB | initializeAllNodes 0:00.00 ( 0.04%) +00:00:04 102MB | writeBucket 0:00.00 ( 0.04%) +00:00:04 102MB | ----------------------------------------------------------------------------------- +00:00:04 102MB | peak CPU memory used 102.81MB +00:00:04 102MB | at startup 36.46MB +00:00:04 102MB | plugins 7.88MB +00:00:04 102MB | AOV samples 3.48MB +00:00:04 102MB | output buffers 1.08MB +00:00:04 102MB | node overhead 0.00MB +00:00:04 102MB | message passing 0.08MB +00:00:04 102MB | memory pools 30.05MB +00:00:04 102MB | geometry 0.00MB +00:00:04 102MB | accel. structs 0.01MB +00:00:04 102MB | strings 12.00MB +00:00:04 102MB | profiler 0.01MB +00:00:04 102MB | unaccounted 11.76MB +00:00:04 102MB | ----------------------------------------------------------------------------------- +00:00:04 102MB | ray counts ( /pixel, /sample) (% total) (avg. hits) (max hits) +00:00:04 102MB | camera 192800 ( 10.04, 1.00) (100.00%) ( 0.11) ( 1) +00:00:04 102MB | total 192800 ( 10.04, 1.00) (100.00%) ( 0.11) ( 1) +00:00:04 102MB | by ray depth: 0 +00:00:04 102MB | total 100.0% +00:00:04 102MB | ----------------------------------------------------------------------------------- +00:00:04 102MB | shader calls ( /pixel, /sample) (% total) +00:00:04 102MB | primary 20327 ( 1.06, 0.11) (100.00%) +00:00:04 102MB | total 20327 ( 1.06, 0.11) (100.00%) +00:00:04 102MB | by ray depth: 0 +00:00:04 102MB | total 100.0% +00:00:04 102MB | ----------------------------------------------------------------------------------- +00:00:04 102MB | geometry (% hit ) (instances) ( init mem, final mem) +00:00:04 102MB | lists 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:04 102MB | procs 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:04 102MB | simple 5 (100.0%) ( 0) ( 0.00, 0.00) +00:00:04 102MB | ----------------------------------------------------------------------------------- +00:00:04 102MB | geometric elements ( min) ( avg.) ( max) +00:00:04 102MB | objects (procs) 5 ( 5) ( 5.0) ( 5) +00:00:04 102MB | ----------------------------------------------------------------------------------- +00:00:04 102MB | acceleration structures: (% total) +00:00:04 102MB | list 1 ( 50.00%) +00:00:04 102MB | bvh 1 ( 50.00%) +00:00:04 102MB | total 2 (100.00%) +00:00:04 102MB | ----------------------------------------------------------------------------------- +00:00:04 102MB | number of warnings, warning type: +00:00:04 102MB | 4: unable to load dynamic library %s: %s +00:00:04 102MB | ----------------------------------------------------------------------------------- +00:00:04 102MB | performance warnings: +00:00:04 102MB WARNING | Rendering utilization was only 2%. Your render may be bound by a single threaded process or I/O. +00:00:04 102MB WARNING | Scene creation was a significant amount of total time (59%). Consider optimizing this process first. +00:00:04 102MB | ----------------------------------------------------------------------------------- +00:00:04 98MB | +00:00:04 98MB | releasing resources +00:00:04 84MB | unloading 5 plugins +00:00:04 84MB | closing mtoa_ParticleInstancer_proc.dll ... +00:00:04 83MB | closing mtoa_ParticleVolume_proc.dll ... +00:00:04 83MB | closing usd_proc.dll ... +00:00:04 83MB | closing alembic_proc.dll ... +00:00:04 83MB | closing cryptomatte.dll ... +00:00:04 83MB | unloading plugins done +00:00:04 83MB | Arnold shutdown diff --git a/testsuite/test_0002/ref/reference.tif b/testsuite/test_0002/ref/reference.tif new file mode 100755 index 0000000000..944f484e77 Binary files /dev/null and b/testsuite/test_0002/ref/reference.tif differ diff --git a/testsuite/test_0003/README b/testsuite/test_0003/README new file mode 100755 index 0000000000..4d3b3a26c3 --- /dev/null +++ b/testsuite/test_0003/README @@ -0,0 +1,4 @@ +Test Dome Lights + +author: sebastien ortega + diff --git a/testsuite/test_0003/data/sphere.usd b/testsuite/test_0003/data/sphere.usd new file mode 100755 index 0000000000..737b55c986 --- /dev/null +++ b/testsuite/test_0003/data/sphere.usd @@ -0,0 +1,11 @@ +#usda 1.0 +( +) + +def Sphere "sphere" +{} + +def DomeLight "dome" +{ + float intensity=2 +} \ No newline at end of file diff --git a/testsuite/test_0003/data/test.ass b/testsuite/test_0003/data/test.ass new file mode 100755 index 0000000000..4eb60cd64b --- /dev/null +++ b/testsuite/test_0003/data/test.ass @@ -0,0 +1,88 @@ +### exported: Mon Dec 17 21:54:24 2018 +### from: Arnold 5.2.2.0 [30b8ba14] windows icc-17.0.2 oiio-2.0.1 osl-1.10.1 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 2018/12/04 22:02:04 +### host app: MtoA 3.1.3.wip 7d48f6c4 (develop) Maya 2018 +### bounds: -1 -8.268288 -1 1 -6.268287 1 +### user: blaines +### render_layer: defaultRenderLayer +### scene: D:/arnold/scenes/usd.ma + + + +options +{ + AA_samples 1 + outputs "RGBA RGBA myfilter mydriver" + xres 160 + yres 120 + pixel_aspect_ratio 1.33333325 + camera "perspShape" + frame 1 + operator "root_op" +} + +gaussian_filter +{ + name myfilter +} + +driver_tiff +{ + name mydriver + filename "testrender.tif" + color_space "sRGB" +} + +persp_camera +{ + name perspShape + matrix + 0.716910601 2.77555756e-17 -0.697165132 0 + -0.320169091 0.888310015 -0.329237103 0 + 0.619298756 0.459244281 0.636838853 0 + 2.41154099 -5.45881033 2.70130825 1 + near_clip 0.100000001 + far_clip 10000 + screen_window_min -1 -1 + screen_window_max 1 1 + shutter_start 0 + shutter_end 0 + shutter_type "box" + rolling_shutter "off" + rolling_shutter_duration 0 + motion_start 0 + motion_end 0 + exposure 0 + fov 54.4322243 + uv_remap 0 0 0 1 + declare maya_full_name constant STRING + maya_full_name "|persp|perspShape" +} + +usd +{ + name usd + visibility 255 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 -7.26828718 0 1 + use_light_group off + override_nodes off + debug on + filename "sphere.usd" +} + +standard_surface +{ + name myshader + base_color 1 0 0 +} + +set_parameter +{ + name root_op + selection "*.(@type == 'shape')" + assignment "shader=\"myshader\"" + +} \ No newline at end of file diff --git a/testsuite/test_0003/ref/reference.log b/testsuite/test_0003/ref/reference.log new file mode 100755 index 0000000000..002cebec52 --- /dev/null +++ b/testsuite/test_0003/ref/reference.log @@ -0,0 +1,238 @@ +00:00:00 52MB | log started Fri Apr 5 18:16:33 2019 +00:00:00 52MB | Arnold 5.3.0.0 [b452526e] windows icc-17.0.2 oiio-2.1.0 osl-1.11.0 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 optix-6.0.0 2019/03/20 01:03:22 +00:00:00 52MB | running on REM8WCK8D2, pid=4148 +00:00:00 52MB | 2 x Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz (20 cores, 40 logical) with 65458MB +00:00:00 52MB | NVIDIA driver version 391.03 +00:00:00 52MB | Windows 7 Enterprise Edition Service Pack 1 (version 6.1, build 7601) +00:00:00 52MB | soft limit for open files raised from 512 to 2048 +00:00:00 52MB | +00:00:00 52MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\plugins ... +00:00:00 52MB | usd_proc.dll: usd uses Arnold 5.3.0.0 +00:00:00 52MB | loaded 1 plugins from 1 lib(s) in 0:00.07 +00:00:00 52MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\bin\..\plugins ... +00:00:00 52MB | usd_proc.dll: usd uses Arnold 5.3.0.0 +00:00:00 52MB WARNING | node "usd" is already installed +00:00:00 52MB | loaded 1 plugins from 1 lib(s) in 0:00.00 +00:00:00 52MB | [kick] command: D:\arnold\releases\Arnold_latest-windows-usd\bin\kick test.ass -dw -r 160 120 -bs 16 -o testrender.tif -set driver_tiff.dither false -nocrashpopup -dp -v 6 -l D:\arnold\releases\Arnold_latest-windows-usd\plugins +00:00:00 52MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\plugins ... +00:00:00 52MB | no plugins loaded +00:00:00 52MB | loading plugins from . ... +00:00:00 52MB | no plugins loaded +00:00:00 52MB | [metadata] loading metadata file: test.ass +00:00:00 53MB | [ass] loading test.ass ... +00:00:00 53MB | [ass] read 1513 bytes, 7 nodes in 0:00.00 +00:00:00 53MB | [kick] applying 1 attr value override +00:00:00 53MB | +00:00:00 53MB | authorizing with default license managers: rlm, clm ... +00:00:02 63MB | [clm] authorized for "86985ARNOL_2018_0F" in 0:02.24 +00:00:02 63MB | [clm] expiration date: permanent, in use: 1/1000 +00:00:02 63MB | +00:00:02 63MB | [color_manager] no color manager is active +00:00:02 63MB | [color_manager] rendering color space is "linear" with declared chromaticities: +00:00:02 63MB | r(0.6400, 0.3300) g(0.3000, 0.6000) b(0.1500, 0.0600) and w(0.3127, 0.3290) +00:00:02 74MB | +00:00:02 74MB | there are 0 lights and 2 objects: +00:00:02 74MB | 1 persp_camera +00:00:02 74MB | 1 utility +00:00:02 74MB | 1 standard_surface +00:00:02 74MB | 1 driver_tiff +00:00:02 74MB | 1 gaussian_filter +00:00:02 74MB | 1 list_aggregate +00:00:02 74MB | 1 set_parameter +00:00:02 74MB | 1 usd +00:00:02 74MB | +00:00:02 74MB | rendering image at 160 x 120, 1 AA sample +00:00:02 74MB | AA samples max +00:00:02 74MB | AA sample clamp +00:00:02 74MB | diffuse +00:00:02 74MB | specular +00:00:02 74MB | transmission samples 2 / depth 2 +00:00:02 74MB | volume indirect +00:00:02 74MB | total depth 10 +00:00:02 74MB | bssrdf samples 2 +00:00:02 74MB | transparency depth 10 +00:00:02 74MB | initializing 9 nodes ... +00:00:02 74MB | [operators] init op: 'root_op' +00:00:02 74MB | [operators] cook op: 'root_op' | node: 'usd' +00:00:02 83MB WARNING | ==== Initializing Usd Reader for procedural usd +00:00:02 83MB WARNING | Object /sphere (type: Sphere) +00:00:02 87MB WARNING | -doubleSided + -extent + -orientation + -primvars:displayColor + -primvars:displayOpacity + -proxyPrim + -purpose + -radius + -visibility + -xformOpOrder + +00:00:02 87MB WARNING | Object /dome (type: DomeLight) +00:00:02 87MB WARNING | -collection:lightLink:includeRoot + -collection:shadowLink:includeRoot + -color + -colorTemperature + -diffuse + -enableColorTemperature + -exposure + -filters + -intensity + -normalize + -portals + -proxyPrim + -purpose + -specular + -texture:file + -texture:format + -visibility + -xformOpOrder + +00:00:02 87MB | [proc] usd: loaded 2 nodes (1 objects, 0 shaders) +00:00:02 87MB | [operators] cook op: 'root_op' | node: 'usd/sphere' +00:00:02 87MB | creating root object list ... +00:00:02 87MB | node initialization done in 0:00.11 (multithreaded) +00:00:02 87MB | [operators] post cook op: 'root_op' +00:00:02 87MB | updating 12 nodes ... +00:00:02 87MB | /dome: skydome_light using 1 sample, 2 volume samples +00:00:02 87MB | scene bounds: (-1 -8.26828766 -1) -> (1 -6.26828718 1) +00:00:02 87MB | node update done in 0:00.00 (multithreaded) +00:00:02 87MB | [aov] parsing 1 output statements ... +00:00:02 87MB | [aov] registered driver: "mydriver" (driver_tiff) +00:00:02 87MB | [aov] * "RGBA" of type RGBA filtered by "myfilter" (gaussian_filter) +00:00:02 87MB | [aov] done preparing 2 AOVs for 1 output to 1 driver (0 deep AOVs) +00:00:02 88MB | starting 40 bucket workers of size 16x16 ... +00:00:02 90MB | 0% done - 1 rays/pixel +00:00:02 93MB | 5% done - 5 rays/pixel +00:00:02 93MB | 10% done - 5 rays/pixel +00:00:02 93MB | 15% done - 6 rays/pixel +00:00:02 93MB | 20% done - 5 rays/pixel +00:00:02 93MB | 25% done - 7 rays/pixel +00:00:02 93MB | 30% done - 4 rays/pixel +00:00:02 93MB | 35% done - 6 rays/pixel +00:00:02 93MB | 40% done - 3 rays/pixel +00:00:02 93MB | 45% done - 2 rays/pixel +00:00:02 94MB | 50% done - 2 rays/pixel +00:00:02 94MB | 55% done - 3 rays/pixel +00:00:02 94MB | 60% done - 5 rays/pixel +00:00:02 94MB | 65% done - 11 rays/pixel +00:00:02 94MB | 70% done - 10 rays/pixel +00:00:02 94MB | 75% done - 10 rays/pixel +00:00:02 94MB | 80% done - 0 rays/pixel +00:00:02 94MB | 85% done - 0 rays/pixel +00:00:02 94MB | 90% done - 0 rays/pixel +00:00:02 94MB | 95% done - 0 rays/pixel +00:00:02 94MB | 100% done - 0 rays/pixel +00:00:02 94MB | render done in 0:00.008 +00:00:02 94MB | [driver_tiff] writing file `testrender.tif' +00:00:02 94MB | render done +00:00:02 94MB | +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | scene creation time 0:00.10 machine utilization (0.00%) +00:00:02 94MB | plugin loading 0:00.08 +00:00:02 94MB | unaccounted 0:00.02 +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | frame time 0:02.40 machine utilization (3.13%) +00:00:02 94MB | node init 0:00.11 +00:00:02 94MB | unaccounted 0:02.26 +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | top session self-times by category +00:00:02 94MB | worker waiting 0:02.36 (96.61%) +00:00:02 94MB | InitializeNodes 0:00.06 ( 2.74%) +00:00:02 94MB | node_init 0:00.00 ( 0.19%) +00:00:02 94MB | initializeAllNodes 0:00.00 ( 0.12%) +00:00:02 94MB | Plugin loader 0:00.00 ( 0.08%) +00:00:02 94MB | TraceCameraRay 0:00.00 ( 0.07%) +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | top session self-times by node +00:00:02 94MB | worker waiting 0:02.36 (96.61%) +00:00:02 94MB | InitializeNodes 0:00.06 ( 2.74%) +00:00:02 94MB | standard_surface:myshader 0:00.00 ( 0.18%) +00:00:02 94MB | usd (node_init) 0:00.00 ( 0.12%) +00:00:02 94MB | initializeAllNodes 0:00.00 ( 0.12%) +00:00:02 94MB | Plugin loader 0:00.00 ( 0.08%) +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | peak CPU memory used 94.88MB +00:00:02 94MB | at startup 36.81MB +00:00:02 94MB | plugins 6.52MB +00:00:02 94MB | AOV samples 0.73MB +00:00:02 94MB | output buffers 0.23MB +00:00:02 94MB | framebuffers 0.31MB +00:00:02 94MB | node overhead 0.01MB +00:00:02 94MB | message passing 0.08MB +00:00:02 94MB | memory pools 30.05MB +00:00:02 94MB | geometry 0.00MB +00:00:02 94MB | strings 12.00MB +00:00:02 94MB | profiler 0.01MB +00:00:02 94MB | unaccounted 8.13MB +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | ray counts ( /pixel, /sample) (% total) (avg. hits) (max hits) +00:00:02 94MB | camera 24160 ( 1.26, 1.00) ( 26.91%) ( 0.34) ( 1) +00:00:02 94MB | shadow 65622 ( 3.42, 2.72) ( 73.09%) ( 0.00) ( 0) +00:00:02 94MB | total 89782 ( 4.68, 3.72) (100.00%) ( 0.09) ( 1) +00:00:02 94MB | by ray depth: 0 +00:00:02 94MB | total 100.0% +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | shader calls ( /pixel, /sample) (% total) +00:00:02 94MB | primary 8215 ( 0.43, 0.34) (100.00%) +00:00:02 94MB | total 8215 ( 0.43, 0.34) (100.00%) +00:00:02 94MB | by ray depth: 0 +00:00:02 94MB | total 100.0% +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | geometry (% hit ) (instances) ( init mem, final mem) +00:00:02 94MB | lists 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 94MB | procs 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 94MB | simple 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | geometric elements ( min) ( avg.) ( max) +00:00:02 94MB | objects (procs) 1 ( 1) ( 1.0) ( 1) +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | acceleration structures: (% total) +00:00:02 94MB | list 2 (100.00%) +00:00:02 94MB | total 2 (100.00%) +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | number of warnings, warning type: +00:00:02 94MB | 1: -collection:lightLink:includeRoot + -collection:shadowLink:includeRoot + -color + -colorTemperature + -diffuse + -enableColorTemperature + -exposure + -filters + -intensity + -normalize + -portals + -proxyPrim + -purpose + -specular + -texture:file + -texture:format + -visibility + -xformOpOrder + +00:00:02 94MB | 1: -doubleSided + -extent + -orientation + -primvars:displayColor + -primvars:displayOpacity + -proxyPrim + -purpose + -radius + -visibility + -xformOpOrder + +00:00:02 94MB | 1: ==== Initializing Usd Reader for procedural usd +00:00:02 94MB | 1: Object /dome (type: DomeLight) +00:00:02 94MB | 1: Object /sphere (type: Sphere) +00:00:02 94MB | 1: node "%s" is already installed +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | performance warnings: +00:00:02 94MB WARNING | Rendering CPU utilization was only 3%. Your render may be bound by a single threaded process or I/O. +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 92MB | +00:00:02 92MB | releasing resources +00:00:02 78MB | unloading 2 plugins +00:00:02 78MB | closing usd_proc.dll ... +00:00:02 78MB | closing usd_proc.dll ... +00:00:02 69MB | unloading plugins done +00:00:02 69MB | Arnold shutdown diff --git a/testsuite/test_0003/ref/reference.tif b/testsuite/test_0003/ref/reference.tif new file mode 100755 index 0000000000..7b821be39e Binary files /dev/null and b/testsuite/test_0003/ref/reference.tif differ diff --git a/testsuite/test_0004/README b/testsuite/test_0004/README new file mode 100755 index 0000000000..827e8b8e50 --- /dev/null +++ b/testsuite/test_0004/README @@ -0,0 +1,4 @@ +Test Distant Lights + +author: sebastien ortega + diff --git a/testsuite/test_0004/data/sphere.usd b/testsuite/test_0004/data/sphere.usd new file mode 100755 index 0000000000..1c03fe00e1 --- /dev/null +++ b/testsuite/test_0004/data/sphere.usd @@ -0,0 +1,11 @@ +#usda 1.0 +( +) + +def Sphere "sphere" +{} + +def DistantLight "distant" +{ +float intensity=2 +} \ No newline at end of file diff --git a/testsuite/test_0004/data/test.ass b/testsuite/test_0004/data/test.ass new file mode 100755 index 0000000000..7ef2053c39 --- /dev/null +++ b/testsuite/test_0004/data/test.ass @@ -0,0 +1,87 @@ +### exported: Mon Dec 17 21:54:24 2018 +### from: Arnold 5.2.2.0 [30b8ba14] windows icc-17.0.2 oiio-2.0.1 osl-1.10.1 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 2018/12/04 22:02:04 +### host app: MtoA 3.1.3.wip 7d48f6c4 (develop) Maya 2018 +### bounds: -1 -8.268288 -1 1 -6.268287 1 +### user: blaines +### render_layer: defaultRenderLayer +### scene: D:/arnold/scenes/usd.ma + + + +options +{ + AA_samples 1 + outputs "RGBA RGBA myfilter mydriver" + xres 160 + yres 120 + pixel_aspect_ratio 1.33333325 + camera "perspShape" + frame 1 + operator "root_op" +} + +gaussian_filter +{ + name myfilter +} + +driver_tiff +{ + name mydriver + filename "testrender.tif" + color_space "sRGB" +} + +persp_camera +{ + name perspShape + matrix + 0.716910601 2.77555756e-17 -0.697165132 0 + -0.320169091 0.888310015 -0.329237103 0 + 0.619298756 0.459244281 0.636838853 0 + 2.41154099 -5.45881033 2.70130825 1 + near_clip 0.100000001 + far_clip 10000 + screen_window_min -1 -1 + screen_window_max 1 1 + shutter_start 0 + shutter_end 0 + shutter_type "box" + rolling_shutter "off" + rolling_shutter_duration 0 + motion_start 0 + motion_end 0 + exposure 0 + fov 54.4322243 + uv_remap 0 0 0 1 + declare maya_full_name constant STRING + maya_full_name "|persp|perspShape" +} + +usd +{ + name usd + visibility 255 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 -7.26828718 0 1 + use_light_group off + override_nodes off + filename "sphere.usd" +} + +standard_surface +{ + name myshader + base_color 1 0 0 +} + +set_parameter +{ + name root_op + selection "usd/*" + assignment "shader=\"myshader\"" + +} \ No newline at end of file diff --git a/testsuite/test_0004/ref/reference.log b/testsuite/test_0004/ref/reference.log new file mode 100755 index 0000000000..114b0c6aeb --- /dev/null +++ b/testsuite/test_0004/ref/reference.log @@ -0,0 +1,174 @@ +00:00:00 52MB | log started Fri Apr 5 18:16:49 2019 +00:00:00 52MB | Arnold 5.3.0.0 [b452526e] windows icc-17.0.2 oiio-2.1.0 osl-1.11.0 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 optix-6.0.0 2019/03/20 01:03:22 +00:00:00 52MB | running on REM8WCK8D2, pid=7856 +00:00:00 52MB | 2 x Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz (20 cores, 40 logical) with 65458MB +00:00:00 52MB | NVIDIA driver version 391.03 +00:00:00 52MB | Windows 7 Enterprise Edition Service Pack 1 (version 6.1, build 7601) +00:00:00 52MB | soft limit for open files raised from 512 to 2048 +00:00:00 52MB | +00:00:00 52MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\plugins ... +00:00:00 52MB | usd_proc.dll: usd uses Arnold 5.3.0.0 +00:00:00 52MB | loaded 1 plugins from 1 lib(s) in 0:00.07 +00:00:00 52MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\bin\..\plugins ... +00:00:00 52MB | usd_proc.dll: usd uses Arnold 5.3.0.0 +00:00:00 52MB WARNING | node "usd" is already installed +00:00:00 52MB | loaded 1 plugins from 1 lib(s) in 0:00.00 +00:00:00 52MB | [kick] command: D:\arnold\releases\Arnold_latest-windows-usd\bin\kick test.ass -dw -r 160 120 -bs 16 -o testrender.tif -set driver_tiff.dither false -nocrashpopup -dp -v 6 -l D:\arnold\releases\Arnold_latest-windows-usd\plugins +00:00:00 52MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\plugins ... +00:00:00 52MB | no plugins loaded +00:00:00 52MB | loading plugins from . ... +00:00:00 52MB | no plugins loaded +00:00:00 52MB | [metadata] loading metadata file: test.ass +00:00:00 53MB | [ass] loading test.ass ... +00:00:00 53MB | [ass] read 1488 bytes, 7 nodes in 0:00.00 +00:00:00 53MB | [kick] applying 1 attr value override +00:00:00 53MB | +00:00:00 53MB | authorizing with default license managers: rlm, clm ... +00:00:02 63MB | [clm] authorized for "86985ARNOL_2018_0F" in 0:02.29 +00:00:02 63MB | [clm] expiration date: permanent, in use: 1/1000 +00:00:02 63MB | +00:00:02 63MB | [color_manager] no color manager is active +00:00:02 63MB | [color_manager] rendering color space is "linear" with declared chromaticities: +00:00:02 63MB | r(0.6400, 0.3300) g(0.3000, 0.6000) b(0.1500, 0.0600) and w(0.3127, 0.3290) +00:00:02 74MB | +00:00:02 74MB | there are 0 lights and 2 objects: +00:00:02 74MB | 1 persp_camera +00:00:02 74MB | 1 utility +00:00:02 74MB | 1 standard_surface +00:00:02 74MB | 1 driver_tiff +00:00:02 74MB | 1 gaussian_filter +00:00:02 74MB | 1 list_aggregate +00:00:02 74MB | 1 set_parameter +00:00:02 74MB | 1 usd +00:00:02 74MB | +00:00:02 74MB | rendering image at 160 x 120, 1 AA sample +00:00:02 74MB | AA samples max +00:00:02 74MB | AA sample clamp +00:00:02 74MB | diffuse +00:00:02 74MB | specular +00:00:02 74MB | transmission samples 2 / depth 2 +00:00:02 74MB | volume indirect +00:00:02 74MB | total depth 10 +00:00:02 74MB | bssrdf samples 2 +00:00:02 74MB | transparency depth 10 +00:00:02 74MB | initializing 9 nodes ... +00:00:02 87MB | [proc] usd: loaded 2 nodes (1 objects, 0 shaders) +00:00:02 87MB | [operators] init op: 'root_op' +00:00:02 87MB | [operators] cook op: 'root_op' | node: 'usd/sphere' +00:00:02 87MB | [operators] cook op: 'root_op' | node: 'usd/distant' +00:00:02 87MB WARNING | [assignment] cannot set user parameter "shader" without type declaration: shader="myshader" +00:00:02 87MB | creating root object list ... +00:00:02 87MB | node initialization done in 0:00.06 (multithreaded) +00:00:02 87MB | [operators] post cook op: 'root_op' +00:00:02 87MB | updating 12 nodes ... +00:00:02 87MB | /distant: distant_light using 1 sample, 2 volume samples +00:00:02 87MB | scene bounds: (-1 -8.26828766 -1) -> (1 -6.26828718 1) +00:00:02 87MB | node update done in 0:00.00 (multithreaded) +00:00:02 87MB | [aov] parsing 1 output statements ... +00:00:02 87MB | [aov] registered driver: "mydriver" (driver_tiff) +00:00:02 87MB | [aov] * "RGBA" of type RGBA filtered by "myfilter" (gaussian_filter) +00:00:02 87MB | [aov] done preparing 2 AOVs for 1 output to 1 driver (0 deep AOVs) +00:00:02 88MB | starting 40 bucket workers of size 16x16 ... +00:00:02 92MB | 0% done - 2 rays/pixel +00:00:02 92MB | 5% done - 2 rays/pixel +00:00:02 93MB | 10% done - 2 rays/pixel +00:00:02 93MB | 15% done - 2 rays/pixel +00:00:02 93MB | 20% done - 2 rays/pixel +00:00:02 93MB | 25% done - 2 rays/pixel +00:00:02 94MB | 30% done - 2 rays/pixel +00:00:02 94MB | 35% done - 2 rays/pixel +00:00:02 94MB | 40% done - 2 rays/pixel +00:00:02 94MB | 45% done - 1 rays/pixel +00:00:02 94MB | 50% done - 1 rays/pixel +00:00:02 94MB | 55% done - 1 rays/pixel +00:00:02 94MB | 60% done - 2 rays/pixel +00:00:02 94MB | 65% done - 2 rays/pixel +00:00:02 94MB | 70% done - 3 rays/pixel +00:00:02 94MB | 75% done - 0 rays/pixel +00:00:02 94MB | 80% done - 0 rays/pixel +00:00:02 94MB | 85% done - 0 rays/pixel +00:00:02 94MB | 90% done - 0 rays/pixel +00:00:02 94MB | 95% done - 0 rays/pixel +00:00:02 95MB | 100% done - 0 rays/pixel +00:00:02 95MB | render done in 0:00.005 +00:00:02 95MB | [driver_tiff] writing file `testrender.tif' +00:00:02 94MB | render done +00:00:02 94MB | +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | scene creation time 0:00.10 machine utilization (0.36%) +00:00:02 94MB | plugin loading 0:00.08 +00:00:02 94MB | unaccounted 0:00.02 +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | frame time 0:02.39 machine utilization (1.72%) +00:00:02 94MB | node init 0:00.06 +00:00:02 94MB | unaccounted 0:02.31 +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | top session self-times by category +00:00:02 94MB | worker waiting 0:02.41 (97.76%) +00:00:02 94MB | InitializeNodes 0:00.04 ( 1.87%) +00:00:02 94MB | Plugin loader 0:00.00 ( 0.08%) +00:00:02 94MB | initializeAllNodes 0:00.00 ( 0.07%) +00:00:02 94MB | node_init (usd) 0:00.00 ( 0.06%) +00:00:02 94MB | thread blocked 0:00.00 ( 0.06%) +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | top session self-times by node +00:00:02 94MB | worker waiting 0:02.41 (97.76%) +00:00:02 94MB | InitializeNodes 0:00.04 ( 1.87%) +00:00:02 94MB | Plugin loader 0:00.00 ( 0.08%) +00:00:02 94MB | initializeAllNodes 0:00.00 ( 0.07%) +00:00:02 94MB | usd (node_init) 0:00.00 ( 0.06%) +00:00:02 94MB | thread blocked 0:00.00 ( 0.06%) +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | peak CPU memory used 95.11MB +00:00:02 94MB | at startup 36.83MB +00:00:02 94MB | plugins 6.55MB +00:00:02 94MB | AOV samples 0.73MB +00:00:02 94MB | output buffers 0.23MB +00:00:02 94MB | framebuffers 0.31MB +00:00:02 94MB | node overhead 0.00MB +00:00:02 94MB | message passing 0.08MB +00:00:02 94MB | memory pools 30.05MB +00:00:02 94MB | geometry 0.00MB +00:00:02 94MB | strings 12.00MB +00:00:02 94MB | profiler 0.01MB +00:00:02 94MB | unaccounted 8.30MB +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | ray counts ( /pixel, /sample) (% total) (avg. hits) (max hits) +00:00:02 94MB | camera 24160 ( 1.26, 1.00) ( 76.36%) ( 0.34) ( 1) +00:00:02 94MB | shadow 7479 ( 0.39, 0.31) ( 23.64%) ( 0.00) ( 0) +00:00:02 94MB | total 31639 ( 1.65, 1.31) (100.00%) ( 0.26) ( 1) +00:00:02 94MB | by ray depth: 0 +00:00:02 94MB | total 100.0% +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | shader calls ( /pixel, /sample) (% total) +00:00:02 94MB | primary 8215 ( 0.43, 0.34) (100.00%) +00:00:02 94MB | total 8215 ( 0.43, 0.34) (100.00%) +00:00:02 94MB | by ray depth: 0 +00:00:02 94MB | total 100.0% +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | geometry (% hit ) (instances) ( init mem, final mem) +00:00:02 94MB | lists 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 94MB | procs 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 94MB | simple 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | geometric elements ( min) ( avg.) ( max) +00:00:02 94MB | objects (procs) 1 ( 1) ( 1.0) ( 1) +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | acceleration structures: (% total) +00:00:02 94MB | list 2 (100.00%) +00:00:02 94MB | total 2 (100.00%) +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | number of warnings, warning type: +00:00:02 94MB | 1: [assignment] cannot set user parameter "%s" without type declaration: %s +00:00:02 94MB | 1: node "%s" is already installed +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | performance warnings: +00:00:02 94MB WARNING | Rendering CPU utilization was only 2%. Your render may be bound by a single threaded process or I/O. +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 91MB | +00:00:02 91MB | releasing resources +00:00:02 79MB | unloading 2 plugins +00:00:02 79MB | closing usd_proc.dll ... +00:00:02 79MB | closing usd_proc.dll ... +00:00:02 70MB | unloading plugins done +00:00:02 70MB | Arnold shutdown diff --git a/testsuite/test_0004/ref/reference.tif b/testsuite/test_0004/ref/reference.tif new file mode 100755 index 0000000000..feaa3e0ef9 Binary files /dev/null and b/testsuite/test_0004/ref/reference.tif differ diff --git a/testsuite/test_0005/README b/testsuite/test_0005/README new file mode 100755 index 0000000000..bcad8db270 --- /dev/null +++ b/testsuite/test_0005/README @@ -0,0 +1,4 @@ +Test Dome Lights with textures + +author: sebastien ortega + diff --git a/testsuite/test_0005/data/ok.tx b/testsuite/test_0005/data/ok.tx new file mode 100755 index 0000000000..f84550a0b6 Binary files /dev/null and b/testsuite/test_0005/data/ok.tx differ diff --git a/testsuite/test_0005/data/sphere.usd b/testsuite/test_0005/data/sphere.usd new file mode 100755 index 0000000000..fe54a8327c --- /dev/null +++ b/testsuite/test_0005/data/sphere.usd @@ -0,0 +1,13 @@ +#usda 1.0 +( +) + +def Sphere "sphere" +{} + +def DomeLight "dome" +{ + float intensity=2 + asset texture:file=@ok.tx@ + +} \ No newline at end of file diff --git a/testsuite/test_0005/data/test.ass b/testsuite/test_0005/data/test.ass new file mode 100755 index 0000000000..86b86bd06c --- /dev/null +++ b/testsuite/test_0005/data/test.ass @@ -0,0 +1,87 @@ +### exported: Mon Dec 17 21:54:24 2018 +### from: Arnold 5.2.2.0 [30b8ba14] windows icc-17.0.2 oiio-2.0.1 osl-1.10.1 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 2018/12/04 22:02:04 +### host app: MtoA 3.1.3.wip 7d48f6c4 (develop) Maya 2018 +### bounds: -1 -8.268288 -1 1 -6.268287 1 +### user: blaines +### render_layer: defaultRenderLayer +### scene: D:/arnold/scenes/usd.ma + + + +options +{ + AA_samples 1 + outputs "RGBA RGBA myfilter mydriver" + xres 160 + yres 120 + pixel_aspect_ratio 1.33333325 + camera "perspShape" + frame 1 + operator "root_op" +} + +gaussian_filter +{ + name myfilter +} + +driver_tiff +{ + name mydriver + filename "testrender.tif" + color_space "sRGB" +} + +persp_camera +{ + name perspShape + matrix + 0.716910601 2.77555756e-17 -0.697165132 0 + -0.320169091 0.888310015 -0.329237103 0 + 0.619298756 0.459244281 0.636838853 0 + 2.41154099 -5.45881033 2.70130825 1 + near_clip 0.100000001 + far_clip 10000 + screen_window_min -1 -1 + screen_window_max 1 1 + shutter_start 0 + shutter_end 0 + shutter_type "box" + rolling_shutter "off" + rolling_shutter_duration 0 + motion_start 0 + motion_end 0 + exposure 0 + fov 54.4322243 + uv_remap 0 0 0 1 + declare maya_full_name constant STRING + maya_full_name "|persp|perspShape" +} + +usd +{ + name usd + visibility 255 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 -7.26828718 0 1 + debug on + use_light_group off + override_nodes off + filename "sphere.usd" +} + +standard_surface +{ + name myshader +} + +set_parameter +{ + name root_op + selection "*.(@type == 'shape')" + assignment "shader=\"myshader\"" + +} \ No newline at end of file diff --git a/testsuite/test_0005/ref/reference.log b/testsuite/test_0005/ref/reference.log new file mode 100755 index 0000000000..0794f9573e --- /dev/null +++ b/testsuite/test_0005/ref/reference.log @@ -0,0 +1,284 @@ +00:00:00 52MB | log started Fri Apr 5 18:17:05 2019 +00:00:00 52MB | Arnold 5.3.0.0 [b452526e] windows icc-17.0.2 oiio-2.1.0 osl-1.11.0 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 optix-6.0.0 2019/03/20 01:03:22 +00:00:00 52MB | running on REM8WCK8D2, pid=2768 +00:00:00 52MB | 2 x Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz (20 cores, 40 logical) with 65458MB +00:00:00 52MB | NVIDIA driver version 391.03 +00:00:00 52MB | Windows 7 Enterprise Edition Service Pack 1 (version 6.1, build 7601) +00:00:00 52MB | soft limit for open files raised from 512 to 2048 +00:00:00 52MB | +00:00:00 52MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\plugins ... +00:00:00 52MB | usd_proc.dll: usd uses Arnold 5.3.0.0 +00:00:00 52MB | loaded 1 plugins from 1 lib(s) in 0:00.07 +00:00:00 52MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\bin\..\plugins ... +00:00:00 52MB | usd_proc.dll: usd uses Arnold 5.3.0.0 +00:00:00 52MB WARNING | node "usd" is already installed +00:00:00 52MB | loaded 1 plugins from 1 lib(s) in 0:00.00 +00:00:00 52MB | [kick] command: D:\arnold\releases\Arnold_latest-windows-usd\bin\kick test.ass -dw -r 160 120 -bs 16 -o testrender.tif -set driver_tiff.dither false -nocrashpopup -dp -v 6 -l D:\arnold\releases\Arnold_latest-windows-usd\plugins +00:00:00 52MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\plugins ... +00:00:00 52MB | no plugins loaded +00:00:00 52MB | loading plugins from . ... +00:00:00 52MB | no plugins loaded +00:00:00 52MB | [metadata] loading metadata file: test.ass +00:00:00 53MB | [ass] loading test.ass ... +00:00:00 53MB | [ass] read 1495 bytes, 7 nodes in 0:00.00 +00:00:00 53MB | [kick] applying 1 attr value override +00:00:00 53MB | +00:00:00 53MB | authorizing with default license managers: rlm, clm ... +00:00:02 63MB | [clm] authorized for "86985ARNOL_2018_0F" in 0:02.30 +00:00:02 63MB | [clm] expiration date: permanent, in use: 1/1000 +00:00:02 63MB | +00:00:02 63MB | [color_manager] no color manager is active +00:00:02 63MB | [color_manager] rendering color space is "linear" with declared chromaticities: +00:00:02 63MB | r(0.6400, 0.3300) g(0.3000, 0.6000) b(0.1500, 0.0600) and w(0.3127, 0.3290) +00:00:02 74MB | +00:00:02 74MB | there are 0 lights and 2 objects: +00:00:02 74MB | 1 persp_camera +00:00:02 74MB | 1 utility +00:00:02 74MB | 1 standard_surface +00:00:02 74MB | 1 driver_tiff +00:00:02 74MB | 1 gaussian_filter +00:00:02 74MB | 1 list_aggregate +00:00:02 74MB | 1 set_parameter +00:00:02 74MB | 1 usd +00:00:02 74MB | +00:00:02 74MB | rendering image at 160 x 120, 1 AA sample +00:00:02 74MB | AA samples max +00:00:02 74MB | AA sample clamp +00:00:02 74MB | diffuse +00:00:02 74MB | specular +00:00:02 74MB | transmission samples 2 / depth 2 +00:00:02 74MB | volume indirect +00:00:02 74MB | total depth 10 +00:00:02 74MB | bssrdf samples 2 +00:00:02 74MB | transparency depth 10 +00:00:02 74MB | initializing 9 nodes ... +00:00:02 75MB | [operators] init op: 'root_op' +00:00:02 75MB | [operators] cook op: 'root_op' | node: 'usd' +00:00:02 83MB WARNING | ==== Initializing Usd Reader for procedural usd +00:00:02 83MB WARNING | Object /sphere (type: Sphere) +00:00:02 87MB WARNING | -doubleSided + -extent + -orientation + -primvars:displayColor + -primvars:displayOpacity + -proxyPrim + -purpose + -radius + -visibility + -xformOpOrder + +00:00:02 87MB WARNING | Object /dome (type: DomeLight) +00:00:02 87MB WARNING | -collection:lightLink:includeRoot + -collection:shadowLink:includeRoot + -color + -colorTemperature + -diffuse + -enableColorTemperature + -exposure + -filters + -intensity + -normalize + -portals + -proxyPrim + -purpose + -specular + -texture:file + -texture:format + -visibility + -xformOpOrder + +00:00:02 87MB | [proc] usd: loaded 3 nodes (1 objects, 1 shaders) +00:00:02 87MB | [operators] cook op: 'root_op' | node: 'usd/sphere' +00:00:02 87MB | creating root object list ... +00:00:02 87MB | node initialization done in 0:00.03 (multithreaded) +00:00:02 87MB | [operators] post cook op: 'root_op' +00:00:02 87MB | updating 13 nodes ... +00:00:02 87MB | /dome: skydome_light using 1 sample, 2 volume samples +00:00:02 87MB | scene bounds: (-1 -8.26828766 -1) -> (1 -6.26828718 1) +00:00:02 87MB | node update done in 0:00.00 (multithreaded) +00:00:02 87MB | [aov] parsing 1 output statements ... +00:00:02 87MB | [aov] registered driver: "mydriver" (driver_tiff) +00:00:02 87MB | [aov] * "RGBA" of type RGBA filtered by "myfilter" (gaussian_filter) +00:00:02 87MB | [aov] done preparing 2 AOVs for 1 output to 1 driver (0 deep AOVs) +00:00:02 88MB | starting 40 bucket workers of size 16x16 ... +00:00:02 89MB | 0% done - 1 rays/pixel +00:00:02 90MB | 5% done - 1 rays/pixel +00:00:02 93MB | 10% done - 1 rays/pixel +00:00:02 94MB | 15% done - 1 rays/pixel +00:00:02 94MB | 20% done - 1 rays/pixel +00:00:02 94MB | 25% done - 1 rays/pixel +00:00:02 94MB | 30% done - 1 rays/pixel +00:00:02 94MB | 35% done - 1 rays/pixel +00:00:02 94MB | 40% done - 1 rays/pixel +00:00:02 94MB | 45% done - 1 rays/pixel +00:00:02 94MB | 50% done - 1 rays/pixel +00:00:02 102MB | [skydome_light] /dome: 1000x1000 importance map done in 0:00.38, average energy 0.333342 +00:00:02 102MB | 55% done - 7 rays/pixel +00:00:02 102MB | [skydome_light] /dome: importance map disabled due to constant color +00:00:02 102MB | 60% done - 8 rays/pixel +00:00:02 102MB | 65% done - 9 rays/pixel +00:00:02 102MB | 70% done - 9 rays/pixel +00:00:02 102MB | 75% done - 11 rays/pixel +00:00:02 102MB | 80% done - 11 rays/pixel +00:00:02 102MB | 85% done - 11 rays/pixel +00:00:02 102MB | 90% done - 14 rays/pixel +00:00:02 102MB | 95% done - 0 rays/pixel +00:00:02 102MB | 100% done - 0 rays/pixel +00:00:02 102MB | render done in 0:00.391 +00:00:02 102MB | [driver_tiff] writing file `testrender.tif' +00:00:02 102MB | render done +00:00:02 102MB | +00:00:02 103MB | ----------------------------------------------------------------------------------- +00:00:02 103MB | scene creation time 0:00.11 machine utilization (0.00%) +00:00:02 103MB | plugin loading 0:00.08 +00:00:02 103MB | unaccounted 0:00.02 +00:00:02 103MB | ----------------------------------------------------------------------------------- +00:00:02 103MB | frame time 0:02.77 machine utilization (11.62%) +00:00:02 103MB | node init 0:00.03 +00:00:02 103MB | rendering 0:00.39 +00:00:02 103MB | importance maps 0:00.36 +00:00:02 103MB | pixel rendering 0:00.02 +00:00:02 103MB | unaccounted 0:02.33 +00:00:02 103MB | ----------------------------------------------------------------------------------- +00:00:02 103MB | top session self-times by category +00:00:02 103MB | worker waiting 0:02.42 (85.16%) +00:00:02 103MB | ImportanceMap initialize (/dome) 0:00.20 ( 7.12%) +00:00:02 103MB | thread blocked 0:00.13 ( 4.72%) +00:00:02 103MB | InitializeNodes 0:00.03 ( 1.30%) +00:00:02 103MB | AiTextureHandleAccess 0:00.03 ( 1.23%) +00:00:02 103MB | TraceCameraRay 0:00.00 ( 0.15%) +00:00:02 103MB | ----------------------------------------------------------------------------------- +00:00:02 103MB | top session self-times by node +00:00:02 103MB | worker waiting 0:02.42 (85.16%) +00:00:02 103MB | skydome_light:/dome 0:00.33 (11.80%) +00:00:02 103MB | ImportanceMap initialize 0:00.20 ( 7.12%) +00:00:02 103MB | thread blocked 0:00.13 ( 4.67%) +00:00:02 103MB | InitializeNodes 0:00.03 ( 1.30%) +00:00:02 103MB | image:/dome/texture_file 0:00.03 ( 1.27%) +00:00:02 103MB | AiTextureHandleAccess 0:00.03 ( 1.23%) +00:00:02 103MB | TraceCameraRay 0:00.00 ( 0.15%) +00:00:02 103MB | standard_surface:myshader 0:00.00 ( 0.13%) +00:00:02 103MB | ----------------------------------------------------------------------------------- +00:00:02 103MB | peak CPU memory used 102.98MB +00:00:02 103MB | at startup 36.84MB +00:00:02 103MB | plugins 6.55MB +00:00:02 103MB | AOV samples 0.73MB +00:00:02 103MB | output buffers 0.23MB +00:00:02 103MB | framebuffers 0.31MB +00:00:02 103MB | node overhead 0.01MB +00:00:02 103MB | message passing 0.08MB +00:00:02 103MB | memory pools 30.05MB +00:00:02 103MB | geometry 0.00MB +00:00:02 103MB | skydome importance map 7.80MB +00:00:02 103MB | strings 12.00MB +00:00:02 103MB | texture cache 0.75MB +00:00:02 103MB | profiler 0.04MB +00:00:02 103MB | unaccounted 7.60MB +00:00:02 103MB | ----------------------------------------------------------------------------------- +00:00:02 103MB | ray counts ( /pixel, /sample) (% total) (avg. hits) (max hits) +00:00:02 103MB | camera 24160 ( 1.26, 1.00) ( 26.91%) ( 0.34) ( 1) +00:00:02 103MB | shadow 65622 ( 3.42, 2.72) ( 73.09%) ( 0.00) ( 0) +00:00:02 103MB | total 89782 ( 4.68, 3.72) (100.00%) ( 0.09) ( 1) +00:00:02 103MB | by ray depth: 0 +00:00:02 103MB | total 100.0% +00:00:02 103MB | ----------------------------------------------------------------------------------- +00:00:02 103MB | shader calls ( /pixel, /sample) (% total) +00:00:02 103MB | primary 8215 ( 0.43, 0.34) ( 0.80%) +00:00:02 103MB | importance 1016064 ( 99.20%) +00:00:02 103MB | total 1024279 ( 53.35, 42.40) (100.00%) +00:00:02 103MB | by ray depth: 0 +00:00:02 103MB | total 100.0% +00:00:02 103MB | ----------------------------------------------------------------------------------- +00:00:02 103MB | geometry (% hit ) (instances) ( init mem, final mem) +00:00:02 103MB | lists 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 103MB | procs 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 103MB | simple 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 103MB | ----------------------------------------------------------------------------------- +00:00:02 103MB | geometric elements ( min) ( avg.) ( max) +00:00:02 103MB | objects (procs) 1 ( 1) ( 1.0) ( 1) +00:00:02 103MB | ----------------------------------------------------------------------------------- +00:00:02 103MB | acceleration structures: (% total) +00:00:02 103MB | list 2 (100.00%) +00:00:02 103MB | total 2 (100.00%) +00:00:02 103MB | ----------------------------------------------------------------------------------- +00:00:02 103MB | OpenImageIO Texture statistics +00:00:02 103MB | Options: gray_to_rgb=1 flip_t=0 max_tile_channels=6 +00:00:02 103MB | Queries/batches : +00:00:02 103MB | texture : 1016064 queries in 1016064 batches +00:00:02 103MB | texture 3d : 0 queries in 0 batches +00:00:02 103MB | shadow : 0 queries in 0 batches +00:00:02 103MB | environment : 0 queries in 0 batches +00:00:02 103MB | Interpolations : +00:00:02 103MB | closest : 0 +00:00:02 103MB | bilinear : 1021564 +00:00:02 103MB | bicubic : 0 +00:00:02 103MB | Average anisotropic probes : 1 +00:00:02 103MB | Max anisotropy in the wild : 1 +00:00:02 103MB | +00:00:02 103MB | OpenImageIO ImageCache statistics (0000000003E30B40) ver 2.1.0dev +00:00:02 103MB | Options: max_memory_MB=2048.0 max_open_files=1536 autotile=0 +00:00:02 103MB | autoscanline=1 automip=1 forcefloat=0 accept_untiled=1 +00:00:02 103MB | accept_unmipped=1 deduplicate=1 unassociatedalpha=0 +00:00:02 103MB | failure_retries=0 +00:00:02 103MB | Images : 1 unique +00:00:02 103MB | ImageInputs : 1 created, 1 current, 1 peak +00:00:02 103MB | Total pixel data size of all images referenced : 399 KB +00:00:02 103MB | Total actual file size of all images referenced : 43 KB +00:00:02 103MB | Pixel data read : 768 KB +00:00:02 103MB | File I/O time : 0.1s (0.0s average per thread, for 40 threads) +00:00:02 103MB | File open time only : 0.0s +00:00:02 103MB | ImageInput mutex locking time : 0.3s +00:00:02 103MB | Tiles: 13 created, 12 current, 12 peak +00:00:02 103MB | total tile requests : 1085147 +00:00:02 103MB | micro-cache misses : 344 (0.0317008%) +00:00:02 103MB | main cache misses : 13 (0.00119799%) +00:00:02 103MB | redundant reads: 0 tiles, 0 B +00:00:02 103MB | Peak cache memory : 768 KB +00:00:02 103MB | Broken or invalid files: 0 +00:00:02 103MB | ----------------------------------------------------------------------------------- +00:00:02 103MB | number of warnings, warning type: +00:00:02 103MB | 1: -collection:lightLink:includeRoot + -collection:shadowLink:includeRoot + -color + -colorTemperature + -diffuse + -enableColorTemperature + -exposure + -filters + -intensity + -normalize + -portals + -proxyPrim + -purpose + -specular + -texture:file + -texture:format + -visibility + -xformOpOrder + +00:00:02 103MB | 1: -doubleSided + -extent + -orientation + -primvars:displayColor + -primvars:displayOpacity + -proxyPrim + -purpose + -radius + -visibility + -xformOpOrder + +00:00:02 103MB | 1: ==== Initializing Usd Reader for procedural usd +00:00:02 103MB | 1: Object /dome (type: DomeLight) +00:00:02 103MB | 1: Object /sphere (type: Sphere) +00:00:02 103MB | 1: node "%s" is already installed +00:00:02 103MB | ----------------------------------------------------------------------------------- +00:00:02 103MB | performance warnings: +00:00:02 103MB WARNING | Rendering CPU utilization was only 12%. Your render may be bound by a single threaded process or I/O. +00:00:02 103MB | ----------------------------------------------------------------------------------- +00:00:02 101MB | +00:00:02 101MB | releasing resources +00:00:03 82MB | unloading 2 plugins +00:00:03 82MB | closing usd_proc.dll ... +00:00:03 82MB | closing usd_proc.dll ... +00:00:03 73MB | unloading plugins done +00:00:03 73MB | Arnold shutdown diff --git a/testsuite/test_0005/ref/reference.tif b/testsuite/test_0005/ref/reference.tif new file mode 100755 index 0000000000..039718ada0 Binary files /dev/null and b/testsuite/test_0005/ref/reference.tif differ diff --git a/testsuite/test_0006/README b/testsuite/test_0006/README new file mode 100755 index 0000000000..2fe734ffdb --- /dev/null +++ b/testsuite/test_0006/README @@ -0,0 +1,4 @@ +Test Disk Lights + +author: sebastien ortega + diff --git a/testsuite/test_0006/data/sphere.usd b/testsuite/test_0006/data/sphere.usd new file mode 100755 index 0000000000..589c2b37a4 --- /dev/null +++ b/testsuite/test_0006/data/sphere.usd @@ -0,0 +1,14 @@ +#usda 1.0 +( +) + +def Sphere "sphere" +{} + +def DiskLight "distant" +{ + float intensity=2 + float radius = 5 + float3 xformOp:translate= (0,0, 5) + uniform token[] xformOpOrder = ["xformOp:translate"] +} \ No newline at end of file diff --git a/testsuite/test_0006/data/test.ass b/testsuite/test_0006/data/test.ass new file mode 100755 index 0000000000..7ef2053c39 --- /dev/null +++ b/testsuite/test_0006/data/test.ass @@ -0,0 +1,87 @@ +### exported: Mon Dec 17 21:54:24 2018 +### from: Arnold 5.2.2.0 [30b8ba14] windows icc-17.0.2 oiio-2.0.1 osl-1.10.1 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 2018/12/04 22:02:04 +### host app: MtoA 3.1.3.wip 7d48f6c4 (develop) Maya 2018 +### bounds: -1 -8.268288 -1 1 -6.268287 1 +### user: blaines +### render_layer: defaultRenderLayer +### scene: D:/arnold/scenes/usd.ma + + + +options +{ + AA_samples 1 + outputs "RGBA RGBA myfilter mydriver" + xres 160 + yres 120 + pixel_aspect_ratio 1.33333325 + camera "perspShape" + frame 1 + operator "root_op" +} + +gaussian_filter +{ + name myfilter +} + +driver_tiff +{ + name mydriver + filename "testrender.tif" + color_space "sRGB" +} + +persp_camera +{ + name perspShape + matrix + 0.716910601 2.77555756e-17 -0.697165132 0 + -0.320169091 0.888310015 -0.329237103 0 + 0.619298756 0.459244281 0.636838853 0 + 2.41154099 -5.45881033 2.70130825 1 + near_clip 0.100000001 + far_clip 10000 + screen_window_min -1 -1 + screen_window_max 1 1 + shutter_start 0 + shutter_end 0 + shutter_type "box" + rolling_shutter "off" + rolling_shutter_duration 0 + motion_start 0 + motion_end 0 + exposure 0 + fov 54.4322243 + uv_remap 0 0 0 1 + declare maya_full_name constant STRING + maya_full_name "|persp|perspShape" +} + +usd +{ + name usd + visibility 255 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 -7.26828718 0 1 + use_light_group off + override_nodes off + filename "sphere.usd" +} + +standard_surface +{ + name myshader + base_color 1 0 0 +} + +set_parameter +{ + name root_op + selection "usd/*" + assignment "shader=\"myshader\"" + +} \ No newline at end of file diff --git a/testsuite/test_0006/ref/reference.log b/testsuite/test_0006/ref/reference.log new file mode 100755 index 0000000000..f27023f0b7 --- /dev/null +++ b/testsuite/test_0006/ref/reference.log @@ -0,0 +1,175 @@ +00:00:00 52MB | log started Fri Apr 5 18:17:25 2019 +00:00:00 52MB | Arnold 5.3.0.0 [b452526e] windows icc-17.0.2 oiio-2.1.0 osl-1.11.0 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 optix-6.0.0 2019/03/20 01:03:22 +00:00:00 52MB | running on REM8WCK8D2, pid=5832 +00:00:00 52MB | 2 x Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz (20 cores, 40 logical) with 65458MB +00:00:00 52MB | NVIDIA driver version 391.03 +00:00:00 52MB | Windows 7 Enterprise Edition Service Pack 1 (version 6.1, build 7601) +00:00:00 52MB | soft limit for open files raised from 512 to 2048 +00:00:00 52MB | +00:00:00 52MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\plugins ... +00:00:00 52MB | usd_proc.dll: usd uses Arnold 5.3.0.0 +00:00:00 52MB | loaded 1 plugins from 1 lib(s) in 0:00.07 +00:00:00 52MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\bin\..\plugins ... +00:00:00 52MB | usd_proc.dll: usd uses Arnold 5.3.0.0 +00:00:00 52MB WARNING | node "usd" is already installed +00:00:00 52MB | loaded 1 plugins from 1 lib(s) in 0:00.00 +00:00:00 52MB | [kick] command: D:\arnold\releases\Arnold_latest-windows-usd\bin\kick test.ass -dw -r 160 120 -bs 16 -o testrender.tif -set driver_tiff.dither false -nocrashpopup -dp -v 6 -l D:\arnold\releases\Arnold_latest-windows-usd\plugins +00:00:00 52MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\plugins ... +00:00:00 52MB | no plugins loaded +00:00:00 52MB | loading plugins from . ... +00:00:00 52MB | no plugins loaded +00:00:00 52MB | [metadata] loading metadata file: test.ass +00:00:00 53MB | [ass] loading test.ass ... +00:00:00 53MB | [ass] read 1488 bytes, 7 nodes in 0:00.00 +00:00:00 53MB | [kick] applying 1 attr value override +00:00:00 53MB | +00:00:00 53MB | authorizing with default license managers: rlm, clm ... +00:00:02 63MB | [clm] authorized for "86985ARNOL_2018_0F" in 0:02.23 +00:00:02 63MB | [clm] expiration date: permanent, in use: 1/1000 +00:00:02 63MB | +00:00:02 63MB | [color_manager] no color manager is active +00:00:02 63MB | [color_manager] rendering color space is "linear" with declared chromaticities: +00:00:02 63MB | r(0.6400, 0.3300) g(0.3000, 0.6000) b(0.1500, 0.0600) and w(0.3127, 0.3290) +00:00:02 74MB | +00:00:02 74MB | there are 0 lights and 2 objects: +00:00:02 74MB | 1 persp_camera +00:00:02 74MB | 1 utility +00:00:02 74MB | 1 standard_surface +00:00:02 74MB | 1 driver_tiff +00:00:02 74MB | 1 gaussian_filter +00:00:02 74MB | 1 list_aggregate +00:00:02 74MB | 1 set_parameter +00:00:02 74MB | 1 usd +00:00:02 74MB | +00:00:02 74MB | rendering image at 160 x 120, 1 AA sample +00:00:02 74MB | AA samples max +00:00:02 74MB | AA sample clamp +00:00:02 74MB | diffuse +00:00:02 74MB | specular +00:00:02 74MB | transmission samples 2 / depth 2 +00:00:02 74MB | volume indirect +00:00:02 74MB | total depth 10 +00:00:02 74MB | bssrdf samples 2 +00:00:02 74MB | transparency depth 10 +00:00:02 74MB | initializing 9 nodes ... +00:00:02 87MB | [proc] usd: loaded 2 nodes (1 objects, 0 shaders) +00:00:02 87MB | [operators] init op: 'root_op' +00:00:02 87MB | [operators] cook op: 'root_op' | node: 'usd/sphere' +00:00:02 87MB | [operators] cook op: 'root_op' | node: 'usd/distant' +00:00:02 87MB WARNING | [assignment] cannot set user parameter "shader" without type declaration: shader="myshader" +00:00:02 87MB | creating root object list ... +00:00:02 87MB | node initialization done in 0:00.03 (multithreaded) +00:00:02 87MB | [operators] post cook op: 'root_op' +00:00:02 87MB | updating 12 nodes ... +00:00:02 87MB | /distant: disk_light using 1 sample, 2 volume samples +00:00:02 87MB | scene bounds: (-1 -8.26828766 -1) -> (1 -6.26828718 1) +00:00:02 87MB | node update done in 0:00.00 (multithreaded) +00:00:02 87MB | [aov] parsing 1 output statements ... +00:00:02 87MB | [aov] registered driver: "mydriver" (driver_tiff) +00:00:02 87MB | [aov] * "RGBA" of type RGBA filtered by "myfilter" (gaussian_filter) +00:00:02 87MB | [aov] done preparing 2 AOVs for 1 output to 1 driver (0 deep AOVs) +00:00:02 88MB | starting 40 bucket workers of size 16x16 ... +00:00:02 92MB | 0% done - 3 rays/pixel +00:00:02 93MB | 5% done - 2 rays/pixel +00:00:02 93MB | 10% done - 2 rays/pixel +00:00:02 93MB | 15% done - 2 rays/pixel +00:00:02 93MB | 20% done - 2 rays/pixel +00:00:02 93MB | 25% done - 2 rays/pixel +00:00:02 94MB | 30% done - 2 rays/pixel +00:00:02 94MB | 35% done - 2 rays/pixel +00:00:02 94MB | 40% done - 2 rays/pixel +00:00:02 94MB | 45% done - 1 rays/pixel +00:00:02 94MB | 50% done - 1 rays/pixel +00:00:02 94MB | 55% done - 1 rays/pixel +00:00:02 94MB | 60% done - 2 rays/pixel +00:00:02 94MB | 65% done - 2 rays/pixel +00:00:02 94MB | 70% done - 0 rays/pixel +00:00:02 94MB | 75% done - 0 rays/pixel +00:00:02 94MB | 80% done - 0 rays/pixel +00:00:02 94MB | 85% done - 0 rays/pixel +00:00:02 94MB | 90% done - 0 rays/pixel +00:00:02 95MB | 95% done - 0 rays/pixel +00:00:02 95MB | 100% done - 0 rays/pixel +00:00:02 95MB | render done in 0:00.006 +00:00:02 95MB | [driver_tiff] writing file `testrender.tif' +00:00:02 95MB | render done +00:00:02 95MB | +00:00:02 95MB | ----------------------------------------------------------------------------------- +00:00:02 95MB | scene creation time 0:00.10 machine utilization (0.36%) +00:00:02 95MB | plugin loading 0:00.08 +00:00:02 95MB | unaccounted 0:00.02 +00:00:02 95MB | ----------------------------------------------------------------------------------- +00:00:02 95MB | frame time 0:02.31 machine utilization (0.76%) +00:00:02 95MB | node init 0:00.03 +00:00:02 95MB | driver init/close 0:00.01 +00:00:02 95MB | unaccounted 0:02.26 +00:00:02 95MB | ----------------------------------------------------------------------------------- +00:00:02 95MB | top session self-times by category +00:00:02 95MB | worker waiting 0:02.35 (98.18%) +00:00:02 95MB | InitializeNodes 0:00.03 ( 1.46%) +00:00:02 95MB | thread blocked 0:00.00 ( 0.08%) +00:00:02 95MB | Plugin loader 0:00.00 ( 0.08%) +00:00:02 95MB | TraceCameraRay 0:00.00 ( 0.05%) +00:00:02 95MB | node_init (usd) 0:00.00 ( 0.04%) +00:00:02 95MB | ----------------------------------------------------------------------------------- +00:00:02 95MB | top session self-times by node +00:00:02 95MB | worker waiting 0:02.35 (98.18%) +00:00:02 95MB | InitializeNodes 0:00.03 ( 1.46%) +00:00:02 95MB | thread blocked 0:00.00 ( 0.08%) +00:00:02 95MB | Plugin loader 0:00.00 ( 0.08%) +00:00:02 95MB | TraceCameraRay 0:00.00 ( 0.05%) +00:00:02 95MB | usd (node_init) 0:00.00 ( 0.04%) +00:00:02 95MB | ----------------------------------------------------------------------------------- +00:00:02 95MB | peak CPU memory used 95.22MB +00:00:02 95MB | at startup 36.84MB +00:00:02 95MB | plugins 6.55MB +00:00:02 95MB | AOV samples 0.73MB +00:00:02 95MB | output buffers 0.23MB +00:00:02 95MB | framebuffers 0.31MB +00:00:02 95MB | node overhead 0.00MB +00:00:02 95MB | message passing 0.08MB +00:00:02 95MB | memory pools 30.05MB +00:00:02 95MB | geometry 0.00MB +00:00:02 95MB | strings 12.00MB +00:00:02 95MB | profiler 0.01MB +00:00:02 95MB | unaccounted 8.41MB +00:00:02 95MB | ----------------------------------------------------------------------------------- +00:00:02 95MB | ray counts ( /pixel, /sample) (% total) (avg. hits) (max hits) +00:00:02 95MB | camera 24160 ( 1.26, 1.00) ( 65.42%) ( 0.34) ( 1) +00:00:02 95MB | shadow 12770 ( 0.67, 0.53) ( 34.58%) ( 0.00) ( 0) +00:00:02 95MB | total 36930 ( 1.92, 1.53) (100.00%) ( 0.22) ( 1) +00:00:02 95MB | by ray depth: 0 +00:00:02 95MB | total 100.0% +00:00:02 95MB | ----------------------------------------------------------------------------------- +00:00:02 95MB | shader calls ( /pixel, /sample) (% total) +00:00:02 95MB | primary 8215 ( 0.43, 0.34) (100.00%) +00:00:02 95MB | total 8215 ( 0.43, 0.34) (100.00%) +00:00:02 95MB | by ray depth: 0 +00:00:02 95MB | total 100.0% +00:00:02 95MB | ----------------------------------------------------------------------------------- +00:00:02 95MB | geometry (% hit ) (instances) ( init mem, final mem) +00:00:02 95MB | lists 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 95MB | procs 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 95MB | simple 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 95MB | ----------------------------------------------------------------------------------- +00:00:02 95MB | geometric elements ( min) ( avg.) ( max) +00:00:02 95MB | objects (procs) 1 ( 1) ( 1.0) ( 1) +00:00:02 95MB | ----------------------------------------------------------------------------------- +00:00:02 95MB | acceleration structures: (% total) +00:00:02 95MB | list 2 (100.00%) +00:00:02 95MB | total 2 (100.00%) +00:00:02 95MB | ----------------------------------------------------------------------------------- +00:00:02 95MB | number of warnings, warning type: +00:00:02 95MB | 1: [assignment] cannot set user parameter "%s" without type declaration: %s +00:00:02 95MB | 1: node "%s" is already installed +00:00:02 95MB | ----------------------------------------------------------------------------------- +00:00:02 95MB | performance warnings: +00:00:02 95MB WARNING | Rendering CPU utilization was only 1%. Your render may be bound by a single threaded process or I/O. +00:00:02 95MB | ----------------------------------------------------------------------------------- +00:00:02 93MB | +00:00:02 93MB | releasing resources +00:00:02 81MB | unloading 2 plugins +00:00:02 81MB | closing usd_proc.dll ... +00:00:02 81MB | closing usd_proc.dll ... +00:00:02 72MB | unloading plugins done +00:00:02 72MB | Arnold shutdown diff --git a/testsuite/test_0006/ref/reference.tif b/testsuite/test_0006/ref/reference.tif new file mode 100755 index 0000000000..027a73c457 Binary files /dev/null and b/testsuite/test_0006/ref/reference.tif differ diff --git a/testsuite/test_0007/README b/testsuite/test_0007/README new file mode 100755 index 0000000000..88f4a04744 --- /dev/null +++ b/testsuite/test_0007/README @@ -0,0 +1,4 @@ +Test Rectangle Lights + +author: sebastien ortega + diff --git a/testsuite/test_0007/data/sphere.usd b/testsuite/test_0007/data/sphere.usd new file mode 100755 index 0000000000..2558fd130d --- /dev/null +++ b/testsuite/test_0007/data/sphere.usd @@ -0,0 +1,15 @@ +#usda 1.0 +( +) + +def Sphere "sphere" +{} + +def RectLight "distant" +{ + float intensity=5 + float width = 1 + float height = 10 + float3 xformOp:translate= (0,0, 5) + uniform token[] xformOpOrder = ["xformOp:translate"] +} \ No newline at end of file diff --git a/testsuite/test_0007/data/test.ass b/testsuite/test_0007/data/test.ass new file mode 100755 index 0000000000..7ef2053c39 --- /dev/null +++ b/testsuite/test_0007/data/test.ass @@ -0,0 +1,87 @@ +### exported: Mon Dec 17 21:54:24 2018 +### from: Arnold 5.2.2.0 [30b8ba14] windows icc-17.0.2 oiio-2.0.1 osl-1.10.1 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 2018/12/04 22:02:04 +### host app: MtoA 3.1.3.wip 7d48f6c4 (develop) Maya 2018 +### bounds: -1 -8.268288 -1 1 -6.268287 1 +### user: blaines +### render_layer: defaultRenderLayer +### scene: D:/arnold/scenes/usd.ma + + + +options +{ + AA_samples 1 + outputs "RGBA RGBA myfilter mydriver" + xres 160 + yres 120 + pixel_aspect_ratio 1.33333325 + camera "perspShape" + frame 1 + operator "root_op" +} + +gaussian_filter +{ + name myfilter +} + +driver_tiff +{ + name mydriver + filename "testrender.tif" + color_space "sRGB" +} + +persp_camera +{ + name perspShape + matrix + 0.716910601 2.77555756e-17 -0.697165132 0 + -0.320169091 0.888310015 -0.329237103 0 + 0.619298756 0.459244281 0.636838853 0 + 2.41154099 -5.45881033 2.70130825 1 + near_clip 0.100000001 + far_clip 10000 + screen_window_min -1 -1 + screen_window_max 1 1 + shutter_start 0 + shutter_end 0 + shutter_type "box" + rolling_shutter "off" + rolling_shutter_duration 0 + motion_start 0 + motion_end 0 + exposure 0 + fov 54.4322243 + uv_remap 0 0 0 1 + declare maya_full_name constant STRING + maya_full_name "|persp|perspShape" +} + +usd +{ + name usd + visibility 255 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 -7.26828718 0 1 + use_light_group off + override_nodes off + filename "sphere.usd" +} + +standard_surface +{ + name myshader + base_color 1 0 0 +} + +set_parameter +{ + name root_op + selection "usd/*" + assignment "shader=\"myshader\"" + +} \ No newline at end of file diff --git a/testsuite/test_0007/ref/reference.log b/testsuite/test_0007/ref/reference.log new file mode 100755 index 0000000000..cf8ae54f13 --- /dev/null +++ b/testsuite/test_0007/ref/reference.log @@ -0,0 +1,174 @@ +00:00:00 52MB | log started Fri Apr 5 18:17:43 2019 +00:00:00 52MB | Arnold 5.3.0.0 [b452526e] windows icc-17.0.2 oiio-2.1.0 osl-1.11.0 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 optix-6.0.0 2019/03/20 01:03:22 +00:00:00 52MB | running on REM8WCK8D2, pid=13636 +00:00:00 52MB | 2 x Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz (20 cores, 40 logical) with 65458MB +00:00:00 52MB | NVIDIA driver version 391.03 +00:00:00 52MB | Windows 7 Enterprise Edition Service Pack 1 (version 6.1, build 7601) +00:00:00 52MB | soft limit for open files raised from 512 to 2048 +00:00:00 52MB | +00:00:00 52MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\plugins ... +00:00:00 52MB | usd_proc.dll: usd uses Arnold 5.3.0.0 +00:00:00 52MB | loaded 1 plugins from 1 lib(s) in 0:00.07 +00:00:00 52MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\bin\..\plugins ... +00:00:00 52MB | usd_proc.dll: usd uses Arnold 5.3.0.0 +00:00:00 52MB WARNING | node "usd" is already installed +00:00:00 52MB | loaded 1 plugins from 1 lib(s) in 0:00.00 +00:00:00 52MB | [kick] command: D:\arnold\releases\Arnold_latest-windows-usd\bin\kick test.ass -dw -r 160 120 -bs 16 -o testrender.tif -set driver_tiff.dither false -nocrashpopup -dp -v 6 -l D:\arnold\releases\Arnold_latest-windows-usd\plugins +00:00:00 52MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\plugins ... +00:00:00 52MB | no plugins loaded +00:00:00 52MB | loading plugins from . ... +00:00:00 52MB | no plugins loaded +00:00:00 52MB | [metadata] loading metadata file: test.ass +00:00:00 53MB | [ass] loading test.ass ... +00:00:00 53MB | [ass] read 1488 bytes, 7 nodes in 0:00.00 +00:00:00 53MB | [kick] applying 1 attr value override +00:00:00 53MB | +00:00:00 53MB | authorizing with default license managers: rlm, clm ... +00:00:02 63MB | [clm] authorized for "86985ARNOL_2018_0F" in 0:02.22 +00:00:02 63MB | [clm] expiration date: permanent, in use: 1/1000 +00:00:02 63MB | +00:00:02 63MB | [color_manager] no color manager is active +00:00:02 63MB | [color_manager] rendering color space is "linear" with declared chromaticities: +00:00:02 63MB | r(0.6400, 0.3300) g(0.3000, 0.6000) b(0.1500, 0.0600) and w(0.3127, 0.3290) +00:00:02 74MB | +00:00:02 74MB | there are 0 lights and 2 objects: +00:00:02 74MB | 1 persp_camera +00:00:02 74MB | 1 utility +00:00:02 74MB | 1 standard_surface +00:00:02 74MB | 1 driver_tiff +00:00:02 74MB | 1 gaussian_filter +00:00:02 74MB | 1 list_aggregate +00:00:02 74MB | 1 set_parameter +00:00:02 74MB | 1 usd +00:00:02 74MB | +00:00:02 74MB | rendering image at 160 x 120, 1 AA sample +00:00:02 74MB | AA samples max +00:00:02 74MB | AA sample clamp +00:00:02 74MB | diffuse +00:00:02 74MB | specular +00:00:02 74MB | transmission samples 2 / depth 2 +00:00:02 74MB | volume indirect +00:00:02 74MB | total depth 10 +00:00:02 74MB | bssrdf samples 2 +00:00:02 74MB | transparency depth 10 +00:00:02 74MB | initializing 9 nodes ... +00:00:02 87MB | [proc] usd: loaded 2 nodes (1 objects, 0 shaders) +00:00:02 87MB | [operators] init op: 'root_op' +00:00:02 87MB | [operators] cook op: 'root_op' | node: 'usd/distant' +00:00:02 87MB | [operators] cook op: 'root_op' | node: 'usd/sphere' +00:00:02 87MB WARNING | [assignment] cannot set user parameter "shader" without type declaration: shader="myshader" +00:00:02 87MB | creating root object list ... +00:00:02 87MB | node initialization done in 0:00.10 (multithreaded) +00:00:02 87MB | [operators] post cook op: 'root_op' +00:00:02 87MB | updating 12 nodes ... +00:00:02 87MB | /distant: quad_light using 1 sample, 2 volume samples +00:00:02 87MB | scene bounds: (-1 -8.26828766 -1) -> (1 -6.26828718 1) +00:00:02 87MB | node update done in 0:00.00 (multithreaded) +00:00:02 88MB | [aov] parsing 1 output statements ... +00:00:02 88MB | [aov] registered driver: "mydriver" (driver_tiff) +00:00:02 88MB | [aov] * "RGBA" of type RGBA filtered by "myfilter" (gaussian_filter) +00:00:02 88MB | [aov] done preparing 2 AOVs for 1 output to 1 driver (0 deep AOVs) +00:00:02 88MB | starting 40 bucket workers of size 16x16 ... +00:00:02 92MB | 0% done - 2 rays/pixel +00:00:02 92MB | 5% done - 2 rays/pixel +00:00:02 93MB | 10% done - 2 rays/pixel +00:00:02 93MB | 15% done - 2 rays/pixel +00:00:02 93MB | 20% done - 2 rays/pixel +00:00:02 93MB | 25% done - 2 rays/pixel +00:00:02 93MB | 30% done - 2 rays/pixel +00:00:02 93MB | 35% done - 2 rays/pixel +00:00:02 93MB | 40% done - 2 rays/pixel +00:00:02 93MB | 45% done - 1 rays/pixel +00:00:02 93MB | 50% done - 1 rays/pixel +00:00:02 93MB | 55% done - 1 rays/pixel +00:00:02 93MB | 60% done - 2 rays/pixel +00:00:02 93MB | 65% done - 2 rays/pixel +00:00:02 93MB | 70% done - 15 rays/pixel +00:00:02 93MB | 75% done - 0 rays/pixel +00:00:02 94MB | 80% done - 0 rays/pixel +00:00:02 94MB | 85% done - 0 rays/pixel +00:00:02 94MB | 90% done - 0 rays/pixel +00:00:02 94MB | 95% done - 0 rays/pixel +00:00:02 94MB | 100% done - 0 rays/pixel +00:00:02 94MB | render done in 0:00.007 +00:00:02 94MB | [driver_tiff] writing file `testrender.tif' +00:00:02 94MB | render done +00:00:02 94MB | +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | scene creation time 0:00.11 machine utilization (0.00%) +00:00:02 94MB | plugin loading 0:00.08 +00:00:02 94MB | unaccounted 0:00.02 +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | frame time 0:02.37 machine utilization (2.74%) +00:00:02 94MB | node init 0:00.10 +00:00:02 94MB | unaccounted 0:02.25 +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | top session self-times by category +00:00:02 94MB | worker waiting 0:02.34 (96.18%) +00:00:02 94MB | InitializeNodes 0:00.07 ( 3.24%) +00:00:02 94MB | node_init 0:00.00 ( 0.11%) +00:00:02 94MB | thread blocked 0:00.00 ( 0.11%) +00:00:02 94MB | initializeAllNodes 0:00.00 ( 0.11%) +00:00:02 94MB | Plugin loader 0:00.00 ( 0.08%) +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | top session self-times by node +00:00:02 94MB | worker waiting 0:02.34 (96.18%) +00:00:02 94MB | InitializeNodes 0:00.07 ( 3.24%) +00:00:02 94MB | thread blocked 0:00.00 ( 0.11%) +00:00:02 94MB | initializeAllNodes 0:00.00 ( 0.11%) +00:00:02 94MB | usd (node_init) 0:00.00 ( 0.11%) +00:00:02 94MB | Plugin loader 0:00.00 ( 0.08%) +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | peak CPU memory used 94.39MB +00:00:02 94MB | at startup 36.84MB +00:00:02 94MB | plugins 6.53MB +00:00:02 94MB | AOV samples 0.73MB +00:00:02 94MB | output buffers 0.23MB +00:00:02 94MB | framebuffers 0.31MB +00:00:02 94MB | node overhead 0.01MB +00:00:02 94MB | message passing 0.08MB +00:00:02 94MB | memory pools 30.05MB +00:00:02 94MB | geometry 0.00MB +00:00:02 94MB | strings 12.00MB +00:00:02 94MB | profiler 0.01MB +00:00:02 94MB | unaccounted 7.60MB +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | ray counts ( /pixel, /sample) (% total) (avg. hits) (max hits) +00:00:02 94MB | camera 24160 ( 1.26, 1.00) ( 72.96%) ( 0.34) ( 1) +00:00:02 94MB | shadow 8956 ( 0.47, 0.37) ( 27.04%) ( 0.00) ( 0) +00:00:02 94MB | total 33116 ( 1.72, 1.37) (100.00%) ( 0.25) ( 1) +00:00:02 94MB | by ray depth: 0 +00:00:02 94MB | total 100.0% +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | shader calls ( /pixel, /sample) (% total) +00:00:02 94MB | primary 8215 ( 0.43, 0.34) (100.00%) +00:00:02 94MB | total 8215 ( 0.43, 0.34) (100.00%) +00:00:02 94MB | by ray depth: 0 +00:00:02 94MB | total 100.0% +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | geometry (% hit ) (instances) ( init mem, final mem) +00:00:02 94MB | lists 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 94MB | procs 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 94MB | simple 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | geometric elements ( min) ( avg.) ( max) +00:00:02 94MB | objects (procs) 1 ( 1) ( 1.0) ( 1) +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | acceleration structures: (% total) +00:00:02 94MB | list 2 (100.00%) +00:00:02 94MB | total 2 (100.00%) +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | number of warnings, warning type: +00:00:02 94MB | 1: [assignment] cannot set user parameter "%s" without type declaration: %s +00:00:02 94MB | 1: node "%s" is already installed +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | performance warnings: +00:00:02 94MB WARNING | Rendering CPU utilization was only 3%. Your render may be bound by a single threaded process or I/O. +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 92MB | +00:00:02 92MB | releasing resources +00:00:02 81MB | unloading 2 plugins +00:00:02 81MB | closing usd_proc.dll ... +00:00:02 81MB | closing usd_proc.dll ... +00:00:02 71MB | unloading plugins done +00:00:02 71MB | Arnold shutdown diff --git a/testsuite/test_0007/ref/reference.tif b/testsuite/test_0007/ref/reference.tif new file mode 100755 index 0000000000..2114217eb1 Binary files /dev/null and b/testsuite/test_0007/ref/reference.tif differ diff --git a/testsuite/test_0008/README b/testsuite/test_0008/README new file mode 100755 index 0000000000..a1492eb4b4 --- /dev/null +++ b/testsuite/test_0008/README @@ -0,0 +1,4 @@ +Test Sphere Lights (with radius) + +author: sebastien ortega + diff --git a/testsuite/test_0008/data/sphere.usd b/testsuite/test_0008/data/sphere.usd new file mode 100755 index 0000000000..6339f9258f --- /dev/null +++ b/testsuite/test_0008/data/sphere.usd @@ -0,0 +1,16 @@ +#usda 1.0 +( +) + +def Sphere "sphere" +{} + +def SphereLight "distant" +{ + float intensity=50 + float exposure=3 + float radius = 5 + float3 xformOp:translate= (0,0, 15) + bool normalize=true + uniform token[] xformOpOrder = ["xformOp:translate"] +} \ No newline at end of file diff --git a/testsuite/test_0008/data/test.ass b/testsuite/test_0008/data/test.ass new file mode 100755 index 0000000000..7ef2053c39 --- /dev/null +++ b/testsuite/test_0008/data/test.ass @@ -0,0 +1,87 @@ +### exported: Mon Dec 17 21:54:24 2018 +### from: Arnold 5.2.2.0 [30b8ba14] windows icc-17.0.2 oiio-2.0.1 osl-1.10.1 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 2018/12/04 22:02:04 +### host app: MtoA 3.1.3.wip 7d48f6c4 (develop) Maya 2018 +### bounds: -1 -8.268288 -1 1 -6.268287 1 +### user: blaines +### render_layer: defaultRenderLayer +### scene: D:/arnold/scenes/usd.ma + + + +options +{ + AA_samples 1 + outputs "RGBA RGBA myfilter mydriver" + xres 160 + yres 120 + pixel_aspect_ratio 1.33333325 + camera "perspShape" + frame 1 + operator "root_op" +} + +gaussian_filter +{ + name myfilter +} + +driver_tiff +{ + name mydriver + filename "testrender.tif" + color_space "sRGB" +} + +persp_camera +{ + name perspShape + matrix + 0.716910601 2.77555756e-17 -0.697165132 0 + -0.320169091 0.888310015 -0.329237103 0 + 0.619298756 0.459244281 0.636838853 0 + 2.41154099 -5.45881033 2.70130825 1 + near_clip 0.100000001 + far_clip 10000 + screen_window_min -1 -1 + screen_window_max 1 1 + shutter_start 0 + shutter_end 0 + shutter_type "box" + rolling_shutter "off" + rolling_shutter_duration 0 + motion_start 0 + motion_end 0 + exposure 0 + fov 54.4322243 + uv_remap 0 0 0 1 + declare maya_full_name constant STRING + maya_full_name "|persp|perspShape" +} + +usd +{ + name usd + visibility 255 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 -7.26828718 0 1 + use_light_group off + override_nodes off + filename "sphere.usd" +} + +standard_surface +{ + name myshader + base_color 1 0 0 +} + +set_parameter +{ + name root_op + selection "usd/*" + assignment "shader=\"myshader\"" + +} \ No newline at end of file diff --git a/testsuite/test_0008/ref/reference.log b/testsuite/test_0008/ref/reference.log new file mode 100755 index 0000000000..2ef0a954e0 --- /dev/null +++ b/testsuite/test_0008/ref/reference.log @@ -0,0 +1,174 @@ +00:00:00 52MB | log started Fri Apr 5 18:18:00 2019 +00:00:00 52MB | Arnold 5.3.0.0 [b452526e] windows icc-17.0.2 oiio-2.1.0 osl-1.11.0 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 optix-6.0.0 2019/03/20 01:03:22 +00:00:00 52MB | running on REM8WCK8D2, pid=6484 +00:00:00 52MB | 2 x Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz (20 cores, 40 logical) with 65458MB +00:00:00 52MB | NVIDIA driver version 391.03 +00:00:00 52MB | Windows 7 Enterprise Edition Service Pack 1 (version 6.1, build 7601) +00:00:00 52MB | soft limit for open files raised from 512 to 2048 +00:00:00 52MB | +00:00:00 52MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\plugins ... +00:00:00 52MB | usd_proc.dll: usd uses Arnold 5.3.0.0 +00:00:00 52MB | loaded 1 plugins from 1 lib(s) in 0:00.07 +00:00:00 52MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\bin\..\plugins ... +00:00:00 52MB | usd_proc.dll: usd uses Arnold 5.3.0.0 +00:00:00 52MB WARNING | node "usd" is already installed +00:00:00 52MB | loaded 1 plugins from 1 lib(s) in 0:00.00 +00:00:00 52MB | [kick] command: D:\arnold\releases\Arnold_latest-windows-usd\bin\kick test.ass -dw -r 160 120 -bs 16 -o testrender.tif -set driver_tiff.dither false -nocrashpopup -dp -v 6 -l D:\arnold\releases\Arnold_latest-windows-usd\plugins +00:00:00 52MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\plugins ... +00:00:00 52MB | no plugins loaded +00:00:00 52MB | loading plugins from . ... +00:00:00 52MB | no plugins loaded +00:00:00 52MB | [metadata] loading metadata file: test.ass +00:00:00 53MB | [ass] loading test.ass ... +00:00:00 53MB | [ass] read 1488 bytes, 7 nodes in 0:00.00 +00:00:00 53MB | [kick] applying 1 attr value override +00:00:00 53MB | +00:00:00 53MB | authorizing with default license managers: rlm, clm ... +00:00:02 63MB | [clm] authorized for "86985ARNOL_2018_0F" in 0:02.73 +00:00:02 63MB | [clm] expiration date: permanent, in use: 1/1000 +00:00:02 63MB | +00:00:02 63MB | [color_manager] no color manager is active +00:00:02 63MB | [color_manager] rendering color space is "linear" with declared chromaticities: +00:00:02 63MB | r(0.6400, 0.3300) g(0.3000, 0.6000) b(0.1500, 0.0600) and w(0.3127, 0.3290) +00:00:02 74MB | +00:00:02 74MB | there are 0 lights and 2 objects: +00:00:02 74MB | 1 persp_camera +00:00:02 74MB | 1 utility +00:00:02 74MB | 1 standard_surface +00:00:02 74MB | 1 driver_tiff +00:00:02 74MB | 1 gaussian_filter +00:00:02 74MB | 1 list_aggregate +00:00:02 74MB | 1 set_parameter +00:00:02 74MB | 1 usd +00:00:02 74MB | +00:00:02 74MB | rendering image at 160 x 120, 1 AA sample +00:00:02 74MB | AA samples max +00:00:02 74MB | AA sample clamp +00:00:02 74MB | diffuse +00:00:02 74MB | specular +00:00:02 74MB | transmission samples 2 / depth 2 +00:00:02 74MB | volume indirect +00:00:02 74MB | total depth 10 +00:00:02 74MB | bssrdf samples 2 +00:00:02 74MB | transparency depth 10 +00:00:02 74MB | initializing 9 nodes ... +00:00:02 86MB | [proc] usd: loaded 2 nodes (1 objects, 0 shaders) +00:00:02 87MB | [operators] init op: 'root_op' +00:00:02 87MB | [operators] cook op: 'root_op' | node: 'usd/sphere' +00:00:02 87MB | [operators] cook op: 'root_op' | node: 'usd/distant' +00:00:02 87MB WARNING | [assignment] cannot set user parameter "shader" without type declaration: shader="myshader" +00:00:02 87MB | creating root object list ... +00:00:02 87MB | node initialization done in 0:00.09 (multithreaded) +00:00:02 87MB | [operators] post cook op: 'root_op' +00:00:02 87MB | updating 12 nodes ... +00:00:02 87MB | /distant: point_light using 1 sample, 2 volume samples +00:00:02 87MB | scene bounds: (-1 -8.26828766 -1) -> (1 -6.26828718 1) +00:00:02 87MB | node update done in 0:00.00 (multithreaded) +00:00:02 87MB | [aov] parsing 1 output statements ... +00:00:02 87MB | [aov] registered driver: "mydriver" (driver_tiff) +00:00:02 87MB | [aov] * "RGBA" of type RGBA filtered by "myfilter" (gaussian_filter) +00:00:02 87MB | [aov] done preparing 2 AOVs for 1 output to 1 driver (0 deep AOVs) +00:00:02 87MB | starting 40 bucket workers of size 16x16 ... +00:00:02 91MB | 0% done - 2 rays/pixel +00:00:02 92MB | 5% done - 2 rays/pixel +00:00:02 93MB | 10% done - 2 rays/pixel +00:00:02 93MB | 15% done - 2 rays/pixel +00:00:02 93MB | 20% done - 1 rays/pixel +00:00:02 93MB | 25% done - 2 rays/pixel +00:00:02 93MB | 30% done - 1 rays/pixel +00:00:02 93MB | 35% done - 2 rays/pixel +00:00:02 93MB | 40% done - 1 rays/pixel +00:00:02 93MB | 45% done - 1 rays/pixel +00:00:02 93MB | 50% done - 1 rays/pixel +00:00:02 93MB | 55% done - 1 rays/pixel +00:00:02 94MB | 60% done - 1 rays/pixel +00:00:02 94MB | 65% done - 2 rays/pixel +00:00:02 94MB | 70% done - 0 rays/pixel +00:00:02 94MB | 75% done - 0 rays/pixel +00:00:02 94MB | 80% done - 0 rays/pixel +00:00:02 94MB | 85% done - 0 rays/pixel +00:00:02 94MB | 90% done - 0 rays/pixel +00:00:02 94MB | 95% done - 0 rays/pixel +00:00:02 94MB | 100% done - 0 rays/pixel +00:00:02 94MB | render done in 0:00.006 +00:00:02 94MB | [driver_tiff] writing file `testrender.tif' +00:00:02 94MB | render done +00:00:02 94MB | +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | scene creation time 0:00.10 machine utilization (0.00%) +00:00:02 94MB | plugin loading 0:00.08 +00:00:02 94MB | unaccounted 0:00.02 +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | frame time 0:02.87 machine utilization (2.09%) +00:00:02 94MB | node init 0:00.09 +00:00:02 94MB | unaccounted 0:02.76 +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | top session self-times by category +00:00:02 94MB | worker waiting 0:02.85 (96.86%) +00:00:02 94MB | InitializeNodes 0:00.08 ( 2.76%) +00:00:02 94MB | node_init (usd) 0:00.00 ( 0.08%) +00:00:02 94MB | initializeAllNodes 0:00.00 ( 0.08%) +00:00:02 94MB | Plugin loader 0:00.00 ( 0.07%) +00:00:02 94MB | thread blocked 0:00.00 ( 0.05%) +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | top session self-times by node +00:00:02 94MB | worker waiting 0:02.85 (96.86%) +00:00:02 94MB | InitializeNodes 0:00.08 ( 2.76%) +00:00:02 94MB | usd (node_init) 0:00.00 ( 0.08%) +00:00:02 94MB | initializeAllNodes 0:00.00 ( 0.08%) +00:00:02 94MB | Plugin loader 0:00.00 ( 0.07%) +00:00:02 94MB | thread blocked 0:00.00 ( 0.05%) +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | peak CPU memory used 94.45MB +00:00:02 94MB | at startup 36.83MB +00:00:02 94MB | plugins 6.55MB +00:00:02 94MB | AOV samples 0.73MB +00:00:02 94MB | output buffers 0.23MB +00:00:02 94MB | framebuffers 0.31MB +00:00:02 94MB | node overhead 0.00MB +00:00:02 94MB | message passing 0.08MB +00:00:02 94MB | memory pools 30.05MB +00:00:02 94MB | geometry 0.00MB +00:00:02 94MB | strings 12.00MB +00:00:02 94MB | profiler 0.01MB +00:00:02 94MB | unaccounted 7.64MB +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | ray counts ( /pixel, /sample) (% total) (avg. hits) (max hits) +00:00:02 94MB | camera 24160 ( 1.26, 1.00) ( 72.37%) ( 0.34) ( 1) +00:00:02 94MB | shadow 9222 ( 0.48, 0.38) ( 27.63%) ( 0.00) ( 0) +00:00:02 94MB | total 33382 ( 1.74, 1.38) (100.00%) ( 0.25) ( 1) +00:00:02 94MB | by ray depth: 0 +00:00:02 94MB | total 100.0% +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | shader calls ( /pixel, /sample) (% total) +00:00:02 94MB | primary 8215 ( 0.43, 0.34) (100.00%) +00:00:02 94MB | total 8215 ( 0.43, 0.34) (100.00%) +00:00:02 94MB | by ray depth: 0 +00:00:02 94MB | total 100.0% +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | geometry (% hit ) (instances) ( init mem, final mem) +00:00:02 94MB | lists 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 94MB | procs 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 94MB | simple 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | geometric elements ( min) ( avg.) ( max) +00:00:02 94MB | objects (procs) 1 ( 1) ( 1.0) ( 1) +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | acceleration structures: (% total) +00:00:02 94MB | list 2 (100.00%) +00:00:02 94MB | total 2 (100.00%) +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | number of warnings, warning type: +00:00:02 94MB | 1: [assignment] cannot set user parameter "%s" without type declaration: %s +00:00:02 94MB | 1: node "%s" is already installed +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | performance warnings: +00:00:02 94MB WARNING | Rendering CPU utilization was only 2%. Your render may be bound by a single threaded process or I/O. +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 91MB | +00:00:02 91MB | releasing resources +00:00:03 78MB | unloading 2 plugins +00:00:03 78MB | closing usd_proc.dll ... +00:00:03 78MB | closing usd_proc.dll ... +00:00:03 69MB | unloading plugins done +00:00:03 69MB | Arnold shutdown diff --git a/testsuite/test_0008/ref/reference.tif b/testsuite/test_0008/ref/reference.tif new file mode 100755 index 0000000000..64509e2c67 Binary files /dev/null and b/testsuite/test_0008/ref/reference.tif differ diff --git a/testsuite/test_0009/README b/testsuite/test_0009/README new file mode 100755 index 0000000000..d01ec66f44 --- /dev/null +++ b/testsuite/test_0009/README @@ -0,0 +1,4 @@ +Test Sphere Lights (no radius) + +author: sebastien ortega + diff --git a/testsuite/test_0009/data/sphere.usd b/testsuite/test_0009/data/sphere.usd new file mode 100755 index 0000000000..d3d4c50414 --- /dev/null +++ b/testsuite/test_0009/data/sphere.usd @@ -0,0 +1,16 @@ +#usda 1.0 +( +) + +def Sphere "sphere" +{} + +def SphereLight "distant" +{ + float exposure=3 + float intensity=15 + float radius = 5 + bool treatAsPoint=true + float3 xformOp:translate= (0,0, 15) + uniform token[] xformOpOrder = ["xformOp:translate"] +} \ No newline at end of file diff --git a/testsuite/test_0009/data/test.ass b/testsuite/test_0009/data/test.ass new file mode 100755 index 0000000000..7ef2053c39 --- /dev/null +++ b/testsuite/test_0009/data/test.ass @@ -0,0 +1,87 @@ +### exported: Mon Dec 17 21:54:24 2018 +### from: Arnold 5.2.2.0 [30b8ba14] windows icc-17.0.2 oiio-2.0.1 osl-1.10.1 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 2018/12/04 22:02:04 +### host app: MtoA 3.1.3.wip 7d48f6c4 (develop) Maya 2018 +### bounds: -1 -8.268288 -1 1 -6.268287 1 +### user: blaines +### render_layer: defaultRenderLayer +### scene: D:/arnold/scenes/usd.ma + + + +options +{ + AA_samples 1 + outputs "RGBA RGBA myfilter mydriver" + xres 160 + yres 120 + pixel_aspect_ratio 1.33333325 + camera "perspShape" + frame 1 + operator "root_op" +} + +gaussian_filter +{ + name myfilter +} + +driver_tiff +{ + name mydriver + filename "testrender.tif" + color_space "sRGB" +} + +persp_camera +{ + name perspShape + matrix + 0.716910601 2.77555756e-17 -0.697165132 0 + -0.320169091 0.888310015 -0.329237103 0 + 0.619298756 0.459244281 0.636838853 0 + 2.41154099 -5.45881033 2.70130825 1 + near_clip 0.100000001 + far_clip 10000 + screen_window_min -1 -1 + screen_window_max 1 1 + shutter_start 0 + shutter_end 0 + shutter_type "box" + rolling_shutter "off" + rolling_shutter_duration 0 + motion_start 0 + motion_end 0 + exposure 0 + fov 54.4322243 + uv_remap 0 0 0 1 + declare maya_full_name constant STRING + maya_full_name "|persp|perspShape" +} + +usd +{ + name usd + visibility 255 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 -7.26828718 0 1 + use_light_group off + override_nodes off + filename "sphere.usd" +} + +standard_surface +{ + name myshader + base_color 1 0 0 +} + +set_parameter +{ + name root_op + selection "usd/*" + assignment "shader=\"myshader\"" + +} \ No newline at end of file diff --git a/testsuite/test_0009/ref/reference.log b/testsuite/test_0009/ref/reference.log new file mode 100755 index 0000000000..93ebb9cce3 --- /dev/null +++ b/testsuite/test_0009/ref/reference.log @@ -0,0 +1,174 @@ +00:00:00 52MB | log started Fri Apr 5 18:18:16 2019 +00:00:00 52MB | Arnold 5.3.0.0 [b452526e] windows icc-17.0.2 oiio-2.1.0 osl-1.11.0 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 optix-6.0.0 2019/03/20 01:03:22 +00:00:00 52MB | running on REM8WCK8D2, pid=13084 +00:00:00 52MB | 2 x Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz (20 cores, 40 logical) with 65458MB +00:00:00 52MB | NVIDIA driver version 391.03 +00:00:00 52MB | Windows 7 Enterprise Edition Service Pack 1 (version 6.1, build 7601) +00:00:00 52MB | soft limit for open files raised from 512 to 2048 +00:00:00 52MB | +00:00:00 52MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\plugins ... +00:00:00 52MB | usd_proc.dll: usd uses Arnold 5.3.0.0 +00:00:00 52MB | loaded 1 plugins from 1 lib(s) in 0:00.07 +00:00:00 52MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\bin\..\plugins ... +00:00:00 52MB | usd_proc.dll: usd uses Arnold 5.3.0.0 +00:00:00 52MB WARNING | node "usd" is already installed +00:00:00 52MB | loaded 1 plugins from 1 lib(s) in 0:00.00 +00:00:00 52MB | [kick] command: D:\arnold\releases\Arnold_latest-windows-usd\bin\kick test.ass -dw -r 160 120 -bs 16 -o testrender.tif -set driver_tiff.dither false -nocrashpopup -dp -v 6 -l D:\arnold\releases\Arnold_latest-windows-usd\plugins +00:00:00 52MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\plugins ... +00:00:00 52MB | no plugins loaded +00:00:00 52MB | loading plugins from . ... +00:00:00 52MB | no plugins loaded +00:00:00 52MB | [metadata] loading metadata file: test.ass +00:00:00 53MB | [ass] loading test.ass ... +00:00:00 53MB | [ass] read 1488 bytes, 7 nodes in 0:00.00 +00:00:00 53MB | [kick] applying 1 attr value override +00:00:00 53MB | +00:00:00 53MB | authorizing with default license managers: rlm, clm ... +00:00:02 63MB | [clm] authorized for "86985ARNOL_2018_0F" in 0:02.21 +00:00:02 63MB | [clm] expiration date: permanent, in use: 1/1000 +00:00:02 63MB | +00:00:02 63MB | [color_manager] no color manager is active +00:00:02 63MB | [color_manager] rendering color space is "linear" with declared chromaticities: +00:00:02 63MB | r(0.6400, 0.3300) g(0.3000, 0.6000) b(0.1500, 0.0600) and w(0.3127, 0.3290) +00:00:02 74MB | +00:00:02 74MB | there are 0 lights and 2 objects: +00:00:02 74MB | 1 persp_camera +00:00:02 74MB | 1 utility +00:00:02 74MB | 1 standard_surface +00:00:02 74MB | 1 driver_tiff +00:00:02 74MB | 1 gaussian_filter +00:00:02 74MB | 1 list_aggregate +00:00:02 74MB | 1 set_parameter +00:00:02 74MB | 1 usd +00:00:02 74MB | +00:00:02 74MB | rendering image at 160 x 120, 1 AA sample +00:00:02 74MB | AA samples max +00:00:02 74MB | AA sample clamp +00:00:02 74MB | diffuse +00:00:02 74MB | specular +00:00:02 74MB | transmission samples 2 / depth 2 +00:00:02 74MB | volume indirect +00:00:02 74MB | total depth 10 +00:00:02 74MB | bssrdf samples 2 +00:00:02 74MB | transparency depth 10 +00:00:02 74MB | initializing 9 nodes ... +00:00:02 87MB | [proc] usd: loaded 2 nodes (1 objects, 0 shaders) +00:00:02 87MB | [operators] init op: 'root_op' +00:00:02 87MB | [operators] cook op: 'root_op' | node: 'usd/distant' +00:00:02 87MB WARNING | [assignment] cannot set user parameter "shader" without type declaration: shader="myshader" +00:00:02 87MB | [operators] cook op: 'root_op' | node: 'usd/sphere' +00:00:02 87MB | creating root object list ... +00:00:02 87MB | node initialization done in 0:00.06 (multithreaded) +00:00:02 87MB | [operators] post cook op: 'root_op' +00:00:02 87MB | updating 12 nodes ... +00:00:02 87MB | /distant: point_light using 1 sample, 2 volume samples +00:00:02 87MB | scene bounds: (-1 -8.26828766 -1) -> (1 -6.26828718 1) +00:00:02 87MB | node update done in 0:00.00 (multithreaded) +00:00:02 87MB | [aov] parsing 1 output statements ... +00:00:02 87MB | [aov] registered driver: "mydriver" (driver_tiff) +00:00:02 87MB | [aov] * "RGBA" of type RGBA filtered by "myfilter" (gaussian_filter) +00:00:02 87MB | [aov] done preparing 2 AOVs for 1 output to 1 driver (0 deep AOVs) +00:00:02 88MB | starting 40 bucket workers of size 16x16 ... +00:00:02 92MB | 0% done - 2 rays/pixel +00:00:02 92MB | 5% done - 2 rays/pixel +00:00:02 93MB | 10% done - 2 rays/pixel +00:00:02 93MB | 15% done - 1 rays/pixel +00:00:02 93MB | 20% done - 2 rays/pixel +00:00:02 93MB | 25% done - 2 rays/pixel +00:00:02 93MB | 30% done - 2 rays/pixel +00:00:02 93MB | 35% done - 2 rays/pixel +00:00:02 94MB | 40% done - 2 rays/pixel +00:00:02 94MB | 45% done - 1 rays/pixel +00:00:02 94MB | 50% done - 1 rays/pixel +00:00:02 94MB | 55% done - 1 rays/pixel +00:00:02 94MB | 60% done - 2 rays/pixel +00:00:02 94MB | 65% done - 2 rays/pixel +00:00:02 94MB | 70% done - 0 rays/pixel +00:00:02 94MB | 75% done - 0 rays/pixel +00:00:02 94MB | 80% done - 0 rays/pixel +00:00:02 94MB | 85% done - 0 rays/pixel +00:00:02 94MB | 90% done - 0 rays/pixel +00:00:02 94MB | 95% done - 0 rays/pixel +00:00:02 94MB | 100% done - 0 rays/pixel +00:00:02 94MB | render done in 0:00.006 +00:00:02 94MB | [driver_tiff] writing file `testrender.tif' +00:00:02 94MB | render done +00:00:02 94MB | +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | scene creation time 0:00.11 machine utilization (0.00%) +00:00:02 94MB | plugin loading 0:00.08 +00:00:02 94MB | unaccounted 0:00.02 +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | frame time 0:02.32 machine utilization (1.66%) +00:00:02 94MB | node init 0:00.06 +00:00:02 94MB | unaccounted 0:02.23 +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | top session self-times by category +00:00:02 94MB | worker waiting 0:02.33 (96.93%) +00:00:02 94MB | InitializeNodes 0:00.06 ( 2.67%) +00:00:02 94MB | Plugin loader 0:00.00 ( 0.09%) +00:00:02 94MB | thread blocked 0:00.00 ( 0.08%) +00:00:02 94MB | node_init (usd) 0:00.00 ( 0.07%) +00:00:02 94MB | initializeAllNodes 0:00.00 ( 0.07%) +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | top session self-times by node +00:00:02 94MB | worker waiting 0:02.33 (96.93%) +00:00:02 94MB | InitializeNodes 0:00.06 ( 2.67%) +00:00:02 94MB | Plugin loader 0:00.00 ( 0.09%) +00:00:02 94MB | thread blocked 0:00.00 ( 0.08%) +00:00:02 94MB | usd (node_init) 0:00.00 ( 0.07%) +00:00:02 94MB | initializeAllNodes 0:00.00 ( 0.07%) +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | peak CPU memory used 94.87MB +00:00:02 94MB | at startup 36.86MB +00:00:02 94MB | plugins 6.56MB +00:00:02 94MB | AOV samples 0.73MB +00:00:02 94MB | output buffers 0.23MB +00:00:02 94MB | framebuffers 0.31MB +00:00:02 94MB | node overhead 0.00MB +00:00:02 94MB | message passing 0.08MB +00:00:02 94MB | memory pools 30.05MB +00:00:02 94MB | geometry 0.00MB +00:00:02 94MB | strings 12.00MB +00:00:02 94MB | profiler 0.01MB +00:00:02 94MB | unaccounted 8.03MB +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | ray counts ( /pixel, /sample) (% total) (avg. hits) (max hits) +00:00:02 94MB | camera 24160 ( 1.26, 1.00) ( 76.97%) ( 0.34) ( 1) +00:00:02 94MB | shadow 7230 ( 0.38, 0.30) ( 23.03%) ( 0.00) ( 0) +00:00:02 94MB | total 31390 ( 1.63, 1.30) (100.00%) ( 0.26) ( 1) +00:00:02 94MB | by ray depth: 0 +00:00:02 94MB | total 100.0% +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | shader calls ( /pixel, /sample) (% total) +00:00:02 94MB | primary 8215 ( 0.43, 0.34) (100.00%) +00:00:02 94MB | total 8215 ( 0.43, 0.34) (100.00%) +00:00:02 94MB | by ray depth: 0 +00:00:02 94MB | total 100.0% +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | geometry (% hit ) (instances) ( init mem, final mem) +00:00:02 94MB | lists 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 94MB | procs 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 94MB | simple 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | geometric elements ( min) ( avg.) ( max) +00:00:02 94MB | objects (procs) 1 ( 1) ( 1.0) ( 1) +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | acceleration structures: (% total) +00:00:02 94MB | list 2 (100.00%) +00:00:02 94MB | total 2 (100.00%) +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | number of warnings, warning type: +00:00:02 94MB | 1: [assignment] cannot set user parameter "%s" without type declaration: %s +00:00:02 94MB | 1: node "%s" is already installed +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 94MB | performance warnings: +00:00:02 94MB WARNING | Rendering CPU utilization was only 2%. Your render may be bound by a single threaded process or I/O. +00:00:02 94MB | ----------------------------------------------------------------------------------- +00:00:02 91MB | +00:00:02 91MB | releasing resources +00:00:02 78MB | unloading 2 plugins +00:00:02 78MB | closing usd_proc.dll ... +00:00:02 78MB | closing usd_proc.dll ... +00:00:02 69MB | unloading plugins done +00:00:02 69MB | Arnold shutdown diff --git a/testsuite/test_0009/ref/reference.tif b/testsuite/test_0009/ref/reference.tif new file mode 100755 index 0000000000..df75601077 Binary files /dev/null and b/testsuite/test_0009/ref/reference.tif differ diff --git a/testsuite/test_0010/README b/testsuite/test_0010/README new file mode 100755 index 0000000000..399b60ee43 --- /dev/null +++ b/testsuite/test_0010/README @@ -0,0 +1,2 @@ +USD references +author: sebastien ortega diff --git a/testsuite/test_0010/data/asset.usda b/testsuite/test_0010/data/asset.usda new file mode 100755 index 0000000000..f3b9dc33b1 --- /dev/null +++ b/testsuite/test_0010/data/asset.usda @@ -0,0 +1,42 @@ +#usda 1.0 +def Xform "root" +{ +def Cube "cube" +{ + double size=2 + float3 xformOp:translate= (4.8,0, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] +} +def Sphere "sphere" +{ + double radius=1.8 + float3 xformOp:translate= (-4.8,0, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] +} + +def Cylinder "cylinder" +{ + double radius=1.1 + double height=3 + token axis="Y" + float3 xformOp:translate= (0,0, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] +} + +def Cone "cone" +{ + double radius=1.6 + double height=2.7 + token axis="X" + float3 xformOp:translate= (0,5, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] +} +def Capsule "capsule" +{ + double radius=1.6 + double height=2.7 + token axis="X" + float3 xformOp:translate= (4,5, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] +} +} \ No newline at end of file diff --git a/testsuite/test_0010/data/shot.usda b/testsuite/test_0010/data/shot.usda new file mode 100755 index 0000000000..3ebe586d03 --- /dev/null +++ b/testsuite/test_0010/data/shot.usda @@ -0,0 +1,7 @@ +#usda 1.0 + +def "refSphere" ( + references = @./asset.usda@ +) +{ +} \ No newline at end of file diff --git a/testsuite/test_0010/data/test.ass b/testsuite/test_0010/data/test.ass new file mode 100755 index 0000000000..9106cc69a4 --- /dev/null +++ b/testsuite/test_0010/data/test.ass @@ -0,0 +1,110 @@ +### exported: Tue Dec 18 15:45:58 2018 +### from: Arnold 5.2.2.0 [30b8ba14] windows icc-17.0.2 oiio-2.0.1 osl-1.10.1 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 2018/12/04 22:02:04 +### host app: MtoA 3.1.3.wip 7d48f6c4 (develop) Maya 2018 +### bounds: -1 -1 -1 1 1 1 +### user: blaines +### render_layer: defaultRenderLayer +### scene: D:/arnold/scenes/usd_builtin.ma + + + +options +{ + AA_samples 3 + AA_samples_max 8 + outputs "RGBA RGBA myfilter mydriver" + xres 960 + yres 540 + texture_per_file_stats on + texture_automip off + camera "perspShape" + frame 1 + GI_diffuse_depth 1 + GI_specular_depth 1 + GI_transmission_depth 8 + declare render_layer constant STRING + render_layer "defaultRenderLayer" +} + +gaussian_filter +{ + name myfilter +} + +driver_tiff +{ + name mydriver + filename "testrender.tif" + color_space "sRGB" +} + +persp_camera +{ + name perspShape + matrix + 0.99999392 -1.08420217e-19 0.00349065149 0 + 0.000781565788 0.974611521 -0.223901182 0 + -0.00340202916 0.223902553 0.97460562 0 + -0.949623287 7.26941013 21.0998859 1 + near_clip 0.100000001 + far_clip 10000 + screen_window_min -1 -1 + screen_window_max 1 1 + shutter_start 0 + shutter_end 0 + shutter_type "box" + rolling_shutter "off" + rolling_shutter_duration 0 + motion_start 0 + motion_end 0 + exposure 0 + fov 34.4322243 + uv_remap 0 0 0 1 + declare maya_full_name constant STRING + maya_full_name "|persp|perspShape" +} + +distant_light +{ + name directionalLightShape1 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 0 0 1 + exposure 0 + cast_shadows on + cast_volumetric_shadows on + shadow_density 1 + samples 1 + normalize on + diffuse 1 + specular 1 + sss 1 + indirect 1 + max_bounces 999 + volume_samples 2 + volume 1 + aov "default" + angle 0 + declare maya_full_name constant STRING + maya_full_name "|directionalLight1|directionalLightShape1" +} + +usd +{ + name aiUsdShape1 + visibility 255 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 0 0 1 + use_light_group off + override_nodes off + filename "shot.usda" + frame 1 + declare maya_full_name constant STRING + maya_full_name "|aiUsd1|aiUsdShape1" +} + diff --git a/testsuite/test_0010/ref/reference.log b/testsuite/test_0010/ref/reference.log new file mode 100755 index 0000000000..e0b12e722a --- /dev/null +++ b/testsuite/test_0010/ref/reference.log @@ -0,0 +1,322 @@ +00:00:02 61MB | log started Thu Dec 27 19:11:12 2018 +00:00:02 61MB | Arnold 5.2.2.0 [62163448] windows icc-17.0.2 oiio-2.0.1 osl-1.10.1 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 2018/12/04 03:55:51 +00:00:02 61MB | running on REM8WCK8D2, pid=19048 +00:00:02 61MB | 2 x Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz (20 cores, 40 logical) with 65458MB +00:00:02 61MB | Nvidia driver version 391.03 +00:00:02 61MB | GPU 0: Quadro K620 @ 1124MHz (compute 5.0) with 2048MB (1477MB available) +00:00:02 61MB | Windows 7 Enterprise Edition Service Pack 1 (version 6.1, build 7601) +00:00:02 61MB | soft limit for open files raised from 512 to 2048 +00:00:02 61MB | +00:00:02 61MB | loading plugins from C:\solidangle\mtoadeploy\2018\procedurals ... +00:00:02 61MB | mtoa_ParticleInstancer_proc.dll: particleInstancer uses Arnold 5.2.2.0 +00:00:02 61MB | mtoa_ParticleVolume_proc.dll: volume_particle uses Arnold 5.2.2.0 +00:00:02 61MB | mtoa_ParticleVolume_proc.dll: implicit_particle uses Arnold 5.2.2.0 +00:00:02 61MB | usd_proc.dll: usd uses Arnold 5.2.2.0 +00:00:02 61MB | [metadata] loading metadata file: C:\solidangle\mtoadeploy\2018\procedurals\usd_proc.mtd +00:00:02 61MB WARNING | unable to load dynamic library C:\solidangle\mtoadeploy\2018\procedurals\xgenSpline_procedural.dll: The specified module could not be found. + + +00:00:02 61MB WARNING | unable to load dynamic library C:\solidangle\mtoadeploy\2018\procedurals\xgen_procedural.dll: The specified module could not be found. + + +00:00:02 61MB | loaded 4 plugins from 3 lib(s) in 0:01.88 +00:00:02 61MB | loading plugins from D:\arnold\releases\Arnold_latest-windows\bin\..\plugins ... +00:00:02 61MB | alembic_proc.dll: alembic uses Arnold 5.2.2.0 +00:00:02 61MB | cryptomatte.dll: cryptomatte uses Arnold 5.2.2.0 +00:00:02 61MB | cryptomatte.dll: cryptomatte_filter uses Arnold 5.2.2.0 +00:00:02 61MB | cryptomatte.dll: cryptomatte_manifest_driver uses Arnold 5.2.2.0 +00:00:02 61MB | loaded 4 plugins from 2 lib(s) in 0:00.00 +00:00:02 61MB | [kick] command: D:\arnold\releases\Arnold_latest-windows\bin\kick test.ass -dw -r 160 120 -bs 16 -o testrender.tif -set driver_tiff.dither false -nocrashpopup -dp -v 6 -l C:\solidangle\mtoadeploy\2018\procedurals +00:00:02 61MB | loading plugins from C:\solidangle\mtoadeploy\2018\procedurals ... +00:00:02 61MB WARNING | unable to load dynamic library C:\solidangle\mtoadeploy\2018\procedurals\xgenSpline_procedural.dll: The specified module could not be found. + + +00:00:02 61MB WARNING | unable to load dynamic library C:\solidangle\mtoadeploy\2018\procedurals\xgen_procedural.dll: The specified module could not be found. + + +00:00:02 61MB | no plugins loaded +00:00:02 61MB | loading plugins from . ... +00:00:02 61MB | no plugins loaded +00:00:02 61MB | [metadata] loading metadata file: test.ass +00:00:02 61MB | [ass] loading test.ass ... +00:00:02 61MB | [ass] read 2109 bytes, 6 nodes in 0:00.00 +00:00:02 61MB | [kick] applying 1 attr value override +00:00:02 61MB | +00:00:02 62MB | authorizing with default license managers: rlm, clm ... +00:00:03 69MB | [clm] authorized for "86985ARNOL_2018_0F" in 0:01.35 +00:00:03 69MB | [clm] expiration date: permanent, in use: 1/100 +00:00:03 69MB | +00:00:03 69MB | [color_manager] no color manager is active +00:00:03 69MB | [color_manager] rendering color space is "linear" with declared chromaticities: +00:00:03 69MB | r(0.6400, 0.3300) g(0.3000, 0.6000) b(0.1500, 0.0600) and w(0.3127, 0.3290) +00:00:03 80MB | +00:00:03 80MB | there are 1 light and 2 objects: +00:00:03 80MB | 1 persp_camera +00:00:03 80MB | 1 distant_light +00:00:03 80MB | 1 utility +00:00:03 80MB | 1 driver_tiff +00:00:03 80MB | 1 gaussian_filter +00:00:03 80MB | 1 list_aggregate +00:00:03 80MB | 1 usd +00:00:03 80MB | +00:00:03 80MB | rendering image at 160 x 120, 3 AA samples +00:00:03 80MB | AA samples max +00:00:03 80MB | AA sample clamp +00:00:03 80MB | diffuse samples 2 / depth 1 +00:00:03 80MB | specular samples 2 / depth 1 +00:00:03 80MB | transmission samples 2 / depth 8 +00:00:03 80MB | volume indirect +00:00:03 80MB | total depth 10 +00:00:03 80MB | bssrdf samples 2 +00:00:03 80MB | transparency depth 10 +00:00:03 80MB | initializing 8 nodes ... +00:00:03 92MB WARNING | ==== Initializing procedural aiUsdShape1 +00:00:03 92MB WARNING | Object /refSphere (type: Xform) +00:00:03 92MB WARNING | -proxyPrim + -purpose + -visibility + -xformOpOrder + +00:00:03 92MB WARNING | Object /refSphere/cube (type: Cube) +00:00:03 92MB WARNING | -doubleSided + -extent + -orientation + -primvars:displayColor + -primvars:displayOpacity + -proxyPrim + -purpose + -size + -visibility + -xformOp:translate + -xformOpOrder + +00:00:03 92MB WARNING | Object /refSphere/sphere (type: Sphere) +00:00:03 92MB WARNING | -doubleSided + -extent + -orientation + -primvars:displayColor + -primvars:displayOpacity + -proxyPrim + -purpose + -radius + -visibility + -xformOp:translate + -xformOpOrder + +00:00:03 92MB WARNING | Object /refSphere/cylinder (type: Cylinder) +00:00:03 92MB WARNING | -axis + -doubleSided + -extent + -height + -orientation + -primvars:displayColor + -primvars:displayOpacity + -proxyPrim + -purpose + -radius + -visibility + -xformOp:translate + -xformOpOrder + +00:00:03 92MB WARNING | Object /refSphere/cone (type: Cone) +00:00:03 92MB WARNING | -axis + -doubleSided + -extent + -height + -orientation + -primvars:displayColor + -primvars:displayOpacity + -proxyPrim + -purpose + -radius + -visibility + -xformOp:translate + -xformOpOrder + +00:00:03 92MB WARNING | Object /refSphere/capsule (type: Capsule) +00:00:03 92MB WARNING | -axis + -doubleSided + -extent + -height + -orientation + -primvars:displayColor + -primvars:displayOpacity + -proxyPrim + -purpose + -radius + -visibility + -xformOp:translate + -xformOpOrder + +00:00:03 92MB | [proc] aiUsdShape1: loaded 5 nodes (5 objects, 0 shaders) +00:00:03 92MB | creating root object list ... +00:00:03 92MB | node initialization done in 0:00.10 (multithreaded) +00:00:03 92MB | updating 14 nodes ... +00:00:03 93MB | directionalLightShape1: distant_light using 1 sample, 2 volume samples +00:00:03 93MB | scene bounds: (-6.60000038 -1.79999995 -1.79999995) -> (5.80000019 6.60000086 1.79999995) +00:00:03 93MB | node update done in 0:00.00 (multithreaded) +00:00:03 93MB | [aov] parsing 1 output statements ... +00:00:03 93MB | [aov] registered driver: "mydriver" (driver_tiff) +00:00:03 93MB | [aov] * "RGBA" of type RGBA filtered by "myfilter" (gaussian_filter) +00:00:03 93MB | [aov] done preparing 2 AOVs for 1 output to 1 driver (0 deep AOVs) +00:00:03 93MB | starting 40 bucket workers of size 16x16 ... +00:00:03 100MB | [accel] procedural bvh4 done - 0:00.00 (wall time) - 5 prims, 1 key +00:00:03 100MB | 0% done - 10 rays/pixel +00:00:03 100MB | 5% done - 10 rays/pixel +00:00:03 100MB | 10% done - 10 rays/pixel +00:00:03 100MB | 15% done - 10 rays/pixel +00:00:03 100MB | 20% done - 10 rays/pixel +00:00:03 100MB | 25% done - 10 rays/pixel +00:00:03 100MB | 30% done - 10 rays/pixel +00:00:03 100MB | 35% done - 10 rays/pixel +00:00:03 101MB | 40% done - 10 rays/pixel +00:00:03 101MB | 45% done - 10 rays/pixel +00:00:03 101MB | 50% done - 10 rays/pixel +00:00:03 101MB | 55% done - 10 rays/pixel +00:00:03 101MB | 60% done - 10 rays/pixel +00:00:03 101MB | 65% done - 10 rays/pixel +00:00:03 101MB | 70% done - 10 rays/pixel +00:00:03 101MB | 75% done - 11 rays/pixel +00:00:03 101MB | 80% done - 0 rays/pixel +00:00:03 101MB | 85% done - 0 rays/pixel +00:00:03 101MB | 90% done - 0 rays/pixel +00:00:03 101MB | 95% done - 0 rays/pixel +00:00:03 101MB | 100% done - 0 rays/pixel +00:00:03 101MB | render done in 0:00.013 +00:00:03 101MB | [driver_tiff] writing file `testrender.tif' +00:00:03 101MB | render done +00:00:03 101MB | +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | scene creation time 0:02.42 machine utilization (0.08%) +00:00:03 101MB | plugin loading 0:02.29 +00:00:03 101MB | unaccounted 0:00.12 +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | frame time 0:01.50 machine utilization (4.50%) +00:00:03 101MB | node init 0:00.10 +00:00:03 101MB | driver init/close 0:00.01 +00:00:03 101MB | rendering 0:00.01 +00:00:03 101MB | pixel rendering 0:00.01 +00:00:03 101MB | unaccounted 0:01.37 +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | top session self-times by category +00:00:03 101MB | worker waiting 0:03.78 (98.14%) +00:00:03 101MB | Plugin loader 0:00.05 ( 1.49%) +00:00:03 101MB | thread blocked 0:00.00 ( 0.09%) +00:00:03 101MB | node_init (aiUsdShape1) 0:00.00 ( 0.07%) +00:00:03 101MB | initializeAllNodes 0:00.00 ( 0.07%) +00:00:03 101MB | TraceCameraRay 0:00.00 ( 0.05%) +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | top session self-times by node +00:00:03 101MB | worker waiting 0:03.78 (98.14%) +00:00:03 101MB | Plugin loader 0:00.05 ( 1.49%) +00:00:03 101MB | usd:aiUsdShape1 0:00.00 ( 0.12%) +00:00:03 101MB | initializeAllNodes 0:00.00 ( 0.07%) +00:00:03 101MB | thread blocked 0:00.00 ( 0.07%) +00:00:03 101MB | TraceCameraRay 0:00.00 ( 0.05%) +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | peak CPU memory used 101.54MB +00:00:03 101MB | at startup 36.43MB +00:00:03 101MB | plugins 8.05MB +00:00:03 101MB | AOV samples 3.48MB +00:00:03 101MB | output buffers 1.08MB +00:00:03 101MB | node overhead 0.00MB +00:00:03 101MB | message passing 0.08MB +00:00:03 101MB | memory pools 30.05MB +00:00:03 101MB | geometry 0.00MB +00:00:03 101MB | accel. structs 0.01MB +00:00:03 101MB | strings 12.00MB +00:00:03 101MB | profiler 0.01MB +00:00:03 101MB | unaccounted 10.35MB +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | ray counts ( /pixel, /sample) (% total) (avg. hits) (max hits) +00:00:03 101MB | camera 192800 ( 10.04, 1.00) (100.00%) ( 0.28) ( 1) +00:00:03 101MB | total 192800 ( 10.04, 1.00) (100.00%) ( 0.28) ( 1) +00:00:03 101MB | by ray depth: 0 +00:00:03 101MB | total 100.0% +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | shader calls ( /pixel, /sample) (% total) +00:00:03 101MB | primary 54714 ( 2.85, 0.28) (100.00%) +00:00:03 101MB | total 54714 ( 2.85, 0.28) (100.00%) +00:00:03 101MB | by ray depth: 0 +00:00:03 101MB | total 100.0% +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | geometry (% hit ) (instances) ( init mem, final mem) +00:00:03 101MB | lists 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:03 101MB | procs 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:03 101MB | simple 5 (100.0%) ( 0) ( 0.00, 0.00) +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | geometric elements ( min) ( avg.) ( max) +00:00:03 101MB | objects (procs) 5 ( 5) ( 5.0) ( 5) +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | acceleration structures: (% total) +00:00:03 101MB | list 1 ( 50.00%) +00:00:03 101MB | bvh 1 ( 50.00%) +00:00:03 101MB | total 2 (100.00%) +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | number of warnings, warning type: +00:00:03 101MB | 3: -axis + -doubleSided + -extent + -height + -orientation + -primvars:displayColor + -primvars:displayOpacity + -proxyPrim + -purpose + -radius + -visibility + -xformOp:translate + -xformOpOrder + +00:00:03 101MB | 1: -doubleSided + -extent + -orientation + -primvars:displayColor + -primvars:displayOpacity + -proxyPrim + -purpose + -radius + -visibility + -xformOp:translate + -xformOpOrder + +00:00:03 101MB | 1: -doubleSided + -extent + -orientation + -primvars:displayColor + -primvars:displayOpacity + -proxyPrim + -purpose + -size + -visibility + -xformOp:translate + -xformOpOrder + +00:00:03 101MB | 1: -proxyPrim + -purpose + -visibility + -xformOpOrder + +00:00:03 101MB | 1: ==== Initializing procedural aiUsdShape1 +00:00:03 101MB | 1: Object /refSphere (type: Xform) +00:00:03 101MB | 1: Object /refSphere/capsule (type: Capsule) +00:00:03 101MB | 1: Object /refSphere/cone (type: Cone) +00:00:03 101MB | 1: Object /refSphere/cube (type: Cube) +00:00:03 101MB | 1: Object /refSphere/cylinder (type: Cylinder) +00:00:03 101MB | 1: Object /refSphere/sphere (type: Sphere) +00:00:03 101MB | 4: unable to load dynamic library %s: %s +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | performance warnings: +00:00:03 101MB WARNING | Rendering utilization was only 5%. Your render may be bound by a single threaded process or I/O. +00:00:03 101MB WARNING | Scene creation was a significant amount of total time (62%). Consider optimizing this process first. +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 96MB | +00:00:03 96MB | releasing resources +00:00:04 83MB | unloading 5 plugins +00:00:04 83MB | closing mtoa_ParticleInstancer_proc.dll ... +00:00:04 83MB | closing mtoa_ParticleVolume_proc.dll ... +00:00:04 83MB | closing usd_proc.dll ... +00:00:04 82MB | closing alembic_proc.dll ... +00:00:04 82MB | closing cryptomatte.dll ... +00:00:04 82MB | unloading plugins done +00:00:04 82MB | Arnold shutdown diff --git a/testsuite/test_0010/ref/reference.tif b/testsuite/test_0010/ref/reference.tif new file mode 100755 index 0000000000..815078766a Binary files /dev/null and b/testsuite/test_0010/ref/reference.tif differ diff --git a/testsuite/test_0011/README b/testsuite/test_0011/README new file mode 100755 index 0000000000..0602cfb2b7 --- /dev/null +++ b/testsuite/test_0011/README @@ -0,0 +1,2 @@ +Alembic references +author: sebastien ortega diff --git a/testsuite/test_0011/data/cubes-hi.abc b/testsuite/test_0011/data/cubes-hi.abc new file mode 100755 index 0000000000..a0fd81ee1c Binary files /dev/null and b/testsuite/test_0011/data/cubes-hi.abc differ diff --git a/testsuite/test_0011/data/shot.usda b/testsuite/test_0011/data/shot.usda new file mode 100755 index 0000000000..c16059a338 --- /dev/null +++ b/testsuite/test_0011/data/shot.usda @@ -0,0 +1,7 @@ +#usda 1.0 + +def "refSphere" ( + references = @./cubes-hi.abc@ +) +{ +} \ No newline at end of file diff --git a/testsuite/test_0011/data/test.ass b/testsuite/test_0011/data/test.ass new file mode 100755 index 0000000000..9106cc69a4 --- /dev/null +++ b/testsuite/test_0011/data/test.ass @@ -0,0 +1,110 @@ +### exported: Tue Dec 18 15:45:58 2018 +### from: Arnold 5.2.2.0 [30b8ba14] windows icc-17.0.2 oiio-2.0.1 osl-1.10.1 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 2018/12/04 22:02:04 +### host app: MtoA 3.1.3.wip 7d48f6c4 (develop) Maya 2018 +### bounds: -1 -1 -1 1 1 1 +### user: blaines +### render_layer: defaultRenderLayer +### scene: D:/arnold/scenes/usd_builtin.ma + + + +options +{ + AA_samples 3 + AA_samples_max 8 + outputs "RGBA RGBA myfilter mydriver" + xres 960 + yres 540 + texture_per_file_stats on + texture_automip off + camera "perspShape" + frame 1 + GI_diffuse_depth 1 + GI_specular_depth 1 + GI_transmission_depth 8 + declare render_layer constant STRING + render_layer "defaultRenderLayer" +} + +gaussian_filter +{ + name myfilter +} + +driver_tiff +{ + name mydriver + filename "testrender.tif" + color_space "sRGB" +} + +persp_camera +{ + name perspShape + matrix + 0.99999392 -1.08420217e-19 0.00349065149 0 + 0.000781565788 0.974611521 -0.223901182 0 + -0.00340202916 0.223902553 0.97460562 0 + -0.949623287 7.26941013 21.0998859 1 + near_clip 0.100000001 + far_clip 10000 + screen_window_min -1 -1 + screen_window_max 1 1 + shutter_start 0 + shutter_end 0 + shutter_type "box" + rolling_shutter "off" + rolling_shutter_duration 0 + motion_start 0 + motion_end 0 + exposure 0 + fov 34.4322243 + uv_remap 0 0 0 1 + declare maya_full_name constant STRING + maya_full_name "|persp|perspShape" +} + +distant_light +{ + name directionalLightShape1 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 0 0 1 + exposure 0 + cast_shadows on + cast_volumetric_shadows on + shadow_density 1 + samples 1 + normalize on + diffuse 1 + specular 1 + sss 1 + indirect 1 + max_bounces 999 + volume_samples 2 + volume 1 + aov "default" + angle 0 + declare maya_full_name constant STRING + maya_full_name "|directionalLight1|directionalLightShape1" +} + +usd +{ + name aiUsdShape1 + visibility 255 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 0 0 1 + use_light_group off + override_nodes off + filename "shot.usda" + frame 1 + declare maya_full_name constant STRING + maya_full_name "|aiUsd1|aiUsdShape1" +} + diff --git a/testsuite/test_0011/ref/reference.log b/testsuite/test_0011/ref/reference.log new file mode 100755 index 0000000000..41c4dec7a8 --- /dev/null +++ b/testsuite/test_0011/ref/reference.log @@ -0,0 +1,527 @@ +00:00:01 60MB | log started Thu Dec 27 18:57:49 2018 +00:00:01 60MB | Arnold 5.2.2.0 [62163448] windows icc-17.0.2 oiio-2.0.1 osl-1.10.1 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 2018/12/04 03:55:51 +00:00:01 60MB | running on REM8WCK8D2, pid=14560 +00:00:01 60MB | 2 x Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz (20 cores, 40 logical) with 65458MB +00:00:01 60MB | Nvidia driver version 391.03 +00:00:01 60MB | GPU 0: Quadro K620 @ 1124MHz (compute 5.0) with 2048MB (1480MB available) +00:00:01 60MB | Windows 7 Enterprise Edition Service Pack 1 (version 6.1, build 7601) +00:00:01 60MB | soft limit for open files raised from 512 to 2048 +00:00:01 60MB | +00:00:01 60MB | loading plugins from C:\solidangle\mtoadeploy\2018\procedurals ... +00:00:01 60MB | mtoa_ParticleInstancer_proc.dll: particleInstancer uses Arnold 5.2.2.0 +00:00:01 60MB | mtoa_ParticleVolume_proc.dll: volume_particle uses Arnold 5.2.2.0 +00:00:01 60MB | mtoa_ParticleVolume_proc.dll: implicit_particle uses Arnold 5.2.2.0 +00:00:01 60MB | usd_proc.dll: usd uses Arnold 5.2.2.0 +00:00:01 60MB | [metadata] loading metadata file: C:\solidangle\mtoadeploy\2018\procedurals\usd_proc.mtd +00:00:01 60MB WARNING | unable to load dynamic library C:\solidangle\mtoadeploy\2018\procedurals\xgenSpline_procedural.dll: The specified module could not be found. + + +00:00:01 60MB WARNING | unable to load dynamic library C:\solidangle\mtoadeploy\2018\procedurals\xgen_procedural.dll: The specified module could not be found. + + +00:00:01 60MB | loaded 4 plugins from 3 lib(s) in 0:01.73 +00:00:01 60MB | loading plugins from D:\arnold\releases\Arnold_latest-windows\bin\..\plugins ... +00:00:01 60MB | alembic_proc.dll: alembic uses Arnold 5.2.2.0 +00:00:01 60MB | cryptomatte.dll: cryptomatte uses Arnold 5.2.2.0 +00:00:01 60MB | cryptomatte.dll: cryptomatte_filter uses Arnold 5.2.2.0 +00:00:01 60MB | cryptomatte.dll: cryptomatte_manifest_driver uses Arnold 5.2.2.0 +00:00:01 60MB | loaded 4 plugins from 2 lib(s) in 0:00.00 +00:00:01 60MB | [kick] command: D:\arnold\releases\Arnold_latest-windows\bin\kick test.ass -dw -r 160 120 -bs 16 -o testrender.tif -set driver_tiff.dither false -nocrashpopup -dp -v 6 -l C:\solidangle\mtoadeploy\2018\procedurals +00:00:01 60MB | loading plugins from C:\solidangle\mtoadeploy\2018\procedurals ... +00:00:02 60MB WARNING | unable to load dynamic library C:\solidangle\mtoadeploy\2018\procedurals\xgenSpline_procedural.dll: The specified module could not be found. + + +00:00:02 60MB WARNING | unable to load dynamic library C:\solidangle\mtoadeploy\2018\procedurals\xgen_procedural.dll: The specified module could not be found. + + +00:00:02 60MB | no plugins loaded +00:00:02 60MB | loading plugins from . ... +00:00:02 60MB | no plugins loaded +00:00:02 60MB | [metadata] loading metadata file: test.ass +00:00:02 61MB | [ass] loading test.ass ... +00:00:02 61MB | [ass] read 2109 bytes, 6 nodes in 0:00.00 +00:00:02 61MB | [kick] applying 1 attr value override +00:00:02 61MB | +00:00:02 61MB | authorizing with default license managers: rlm, clm ... +00:00:03 69MB | [clm] authorized for "86985ARNOL_2018_0F" in 0:01.22 +00:00:03 69MB | [clm] expiration date: permanent, in use: 1/100 +00:00:03 69MB | +00:00:03 69MB | [color_manager] no color manager is active +00:00:03 69MB | [color_manager] rendering color space is "linear" with declared chromaticities: +00:00:03 69MB | r(0.6400, 0.3300) g(0.3000, 0.6000) b(0.1500, 0.0600) and w(0.3127, 0.3290) +00:00:03 80MB | +00:00:03 80MB | there are 1 light and 2 objects: +00:00:03 80MB | 1 persp_camera +00:00:03 80MB | 1 distant_light +00:00:03 80MB | 1 utility +00:00:03 80MB | 1 driver_tiff +00:00:03 80MB | 1 gaussian_filter +00:00:03 80MB | 1 list_aggregate +00:00:03 80MB | 1 usd +00:00:03 80MB | +00:00:03 80MB | rendering image at 160 x 120, 3 AA samples +00:00:03 80MB | AA samples max +00:00:03 80MB | AA sample clamp +00:00:03 80MB | diffuse samples 2 / depth 1 +00:00:03 80MB | specular samples 2 / depth 1 +00:00:03 80MB | transmission samples 2 / depth 8 +00:00:03 80MB | volume indirect +00:00:03 80MB | total depth 10 +00:00:03 80MB | bssrdf samples 2 +00:00:03 80MB | transparency depth 10 +00:00:03 80MB | initializing 8 nodes ... +00:00:03 104MB WARNING | ==== Initializing procedural aiUsdShape1 +00:00:03 99MB WARNING | ///////////////////////////////////////////////////////////////////Object /refSphere (type: Mesh) +00:00:03 99MB WARNING | -cornerIndices + -cornerSharpnesses + -creaseIndices + -creaseLengths + -creaseSharpnesses + -doubleSided + -extent + -faceVaryingLinearInterpolation + -faceVertexCounts + -faceVertexIndices + -holeIndices + -interpolateBoundary + -normals + -orientation + -points + -primvars:displayColor + -primvars:displayOpacity + -primvars:normals + -primvars:uv + -primvars:uv:indices + -proxyPrim + -purpose + -subdivisionScheme + -triangleSubdivisionRule + -velocities + -visibility + -xformOpOrder + +00:00:03 99MB WARNING | =============== EXPORTING MEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEESG +00:00:03 99MB WARNING | /refSphere +00:00:03 99MB WARNING | =============== voilaaaaa +00:00:03 99MB WARNING | =============== A +00:00:03 99MB WARNING | =============== EXPORTed vidx +00:00:03 99MB WARNING | =============== EXPORTed vlist +00:00:03 99MB WARNING | [usd] none subdivision scheme not supported for mesh on path /refSphere +00:00:03 99MB WARNING | =============== PUSHING NODE +00:00:03 99MB WARNING | ///////////////////////////////////////////////////////////////////Object /refSphere/pCube2 (type: Mesh) +00:00:03 99MB WARNING | -cornerIndices + -cornerSharpnesses + -creaseIndices + -creaseLengths + -creaseSharpnesses + -doubleSided + -extent + -faceVaryingLinearInterpolation + -faceVertexCounts + -faceVertexIndices + -holeIndices + -interpolateBoundary + -normals + -orientation + -points + -primvars:displayColor + -primvars:displayOpacity + -primvars:normals + -primvars:uv + -primvars:uv:indices + -proxyPrim + -purpose + -subdivisionScheme + -triangleSubdivisionRule + -velocities + -visibility + -xformOp:transform + -xformOpOrder + +00:00:03 99MB WARNING | =============== EXPORTING MEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEESG +00:00:03 99MB WARNING | /refSphere/pCube2 +00:00:03 99MB WARNING | =============== voilaaaaa +00:00:03 99MB WARNING | =============== A +00:00:03 99MB WARNING | =============== EXPORTed vidx +00:00:03 99MB WARNING | =============== EXPORTed vlist +00:00:03 99MB WARNING | [usd] none subdivision scheme not supported for mesh on path /refSphere/pCube2 +00:00:03 99MB WARNING | =============== PUSHING NODE +00:00:03 99MB WARNING | ///////////////////////////////////////////////////////////////////Object /refSphere/pCube2/pCube5 (type: Mesh) +00:00:03 99MB WARNING | -cornerIndices + -cornerSharpnesses + -creaseIndices + -creaseLengths + -creaseSharpnesses + -doubleSided + -extent + -faceVaryingLinearInterpolation + -faceVertexCounts + -faceVertexIndices + -holeIndices + -interpolateBoundary + -normals + -orientation + -points + -primvars:displayColor + -primvars:displayOpacity + -primvars:normals + -primvars:uv + -primvars:uv:indices + -proxyPrim + -purpose + -subdivisionScheme + -triangleSubdivisionRule + -velocities + -visibility + -xformOp:transform + -xformOpOrder + +00:00:03 99MB WARNING | =============== EXPORTING MEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEESG +00:00:03 99MB WARNING | /refSphere/pCube2/pCube5 +00:00:03 99MB WARNING | =============== voilaaaaa +00:00:03 99MB WARNING | =============== A +00:00:03 99MB WARNING | =============== EXPORTed vidx +00:00:03 99MB WARNING | =============== EXPORTed vlist +00:00:03 99MB WARNING | [usd] none subdivision scheme not supported for mesh on path /refSphere/pCube2/pCube5 +00:00:03 99MB WARNING | =============== PUSHING NODE +00:00:03 99MB WARNING | ///////////////////////////////////////////////////////////////////Object /refSphere/pCube2/pCube5/pCube6 (type: Mesh) +00:00:03 99MB WARNING | -cornerIndices + -cornerSharpnesses + -creaseIndices + -creaseLengths + -creaseSharpnesses + -doubleSided + -extent + -faceVaryingLinearInterpolation + -faceVertexCounts + -faceVertexIndices + -holeIndices + -interpolateBoundary + -normals + -orientation + -points + -primvars:displayColor + -primvars:displayOpacity + -primvars:normals + -primvars:uv + -primvars:uv:indices + -proxyPrim + -purpose + -subdivisionScheme + -triangleSubdivisionRule + -velocities + -visibility + -xformOp:transform + -xformOpOrder + +00:00:03 99MB WARNING | =============== EXPORTING MEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEESG +00:00:03 99MB WARNING | /refSphere/pCube2/pCube5/pCube6 +00:00:03 99MB WARNING | =============== voilaaaaa +00:00:03 99MB WARNING | =============== A +00:00:03 99MB WARNING | =============== EXPORTed vidx +00:00:03 99MB WARNING | =============== EXPORTed vlist +00:00:03 99MB WARNING | [usd] none subdivision scheme not supported for mesh on path /refSphere/pCube2/pCube5/pCube6 +00:00:03 99MB WARNING | =============== PUSHING NODE +00:00:03 99MB WARNING | ///////////////////////////////////////////////////////////////////Object /refSphere/pCube3 (type: Mesh) +00:00:03 99MB WARNING | -cornerIndices + -cornerSharpnesses + -creaseIndices + -creaseLengths + -creaseSharpnesses + -doubleSided + -extent + -faceVaryingLinearInterpolation + -faceVertexCounts + -faceVertexIndices + -holeIndices + -interpolateBoundary + -normals + -orientation + -points + -primvars:displayColor + -primvars:displayOpacity + -primvars:normals + -primvars:uv + -primvars:uv:indices + -proxyPrim + -purpose + -subdivisionScheme + -triangleSubdivisionRule + -velocities + -visibility + -xformOp:transform + -xformOpOrder + +00:00:03 99MB WARNING | =============== EXPORTING MEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEESG +00:00:03 99MB WARNING | /refSphere/pCube3 +00:00:03 99MB WARNING | =============== voilaaaaa +00:00:03 99MB WARNING | =============== A +00:00:03 99MB WARNING | =============== EXPORTed vidx +00:00:03 99MB WARNING | =============== EXPORTed vlist +00:00:03 99MB WARNING | [usd] none subdivision scheme not supported for mesh on path /refSphere/pCube3 +00:00:03 100MB WARNING | =============== PUSHING NODE +00:00:03 100MB WARNING | ///////////////////////////////////////////////////////////////////Object /refSphere/pCube3/pCube4 (type: Mesh) +00:00:03 100MB WARNING | -cornerIndices + -cornerSharpnesses + -creaseIndices + -creaseLengths + -creaseSharpnesses + -doubleSided + -extent + -faceVaryingLinearInterpolation + -faceVertexCounts + -faceVertexIndices + -holeIndices + -interpolateBoundary + -normals + -orientation + -points + -primvars:displayColor + -primvars:displayOpacity + -primvars:normals + -primvars:uv + -primvars:uv:indices + -proxyPrim + -purpose + -subdivisionScheme + -triangleSubdivisionRule + -velocities + -visibility + -xformOp:transform + -xformOpOrder + +00:00:03 100MB WARNING | /refSphere/pCube3/pCube4 +00:00:03 100MB WARNING | ///////////////////////////////////////////////////////////////////Object /refSphere/pCube3/pCube4/pCube7 (type: Mesh) +00:00:03 100MB WARNING | /refSphere/pCube3/pCube4/pCube7 +00:00:03 100MB | [proc] aiUsdShape1: loaded 7 nodes (7 objects, 0 shaders) +00:00:03 101MB | creating root object list ... +00:00:03 101MB | node initialization done in 0:00.11 (multithreaded) +00:00:03 101MB | updating 16 nodes ... +00:00:03 101MB | directionalLightShape1: distant_light using 1 sample, 2 volume samples +00:00:03 101MB | scene bounds: (-2.5 -0.5 -1.5) -> (2.5 1.5 1.5) +00:00:03 101MB | node update done in 0:00.00 (multithreaded) +00:00:03 101MB | [aov] parsing 1 output statements ... +00:00:03 101MB | [aov] registered driver: "mydriver" (driver_tiff) +00:00:03 101MB | [aov] * "RGBA" of type RGBA filtered by "myfilter" (gaussian_filter) +00:00:03 101MB | [aov] done preparing 2 AOVs for 1 output to 1 driver (0 deep AOVs) +00:00:03 101MB | starting 40 bucket workers of size 16x16 ... +00:00:03 105MB | [accel] procedural bvh4 done - 0:00.00 (wall time) - 7 prims, 1 key +00:00:03 107MB | 0% done - 10 rays/pixel +00:00:03 107MB | 5% done - 10 rays/pixel +00:00:03 107MB | 10% done - 10 rays/pixel +00:00:03 107MB | 15% done - 10 rays/pixel +00:00:03 108MB | 20% done - 10 rays/pixel +00:00:03 108MB | 25% done - 10 rays/pixel +00:00:03 108MB | 30% done - 10 rays/pixel +00:00:03 108MB | 35% done - 10 rays/pixel +00:00:03 108MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 8800 prims, 1 key +00:00:03 108MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 8800 prims, 1 key +00:00:03 108MB | 40% done - 10 rays/pixel +00:00:03 108MB | 45% done - 12 rays/pixel +00:00:03 108MB | 50% done - 11 rays/pixel +00:00:03 108MB | 55% done - 10 rays/pixel +00:00:03 108MB | 60% done - 10 rays/pixel +00:00:03 108MB | 65% done - 10 rays/pixel +00:00:03 109MB | 70% done - 10 rays/pixel +00:00:03 109MB | 75% done - 10 rays/pixel +00:00:03 109MB | 80% done - 11 rays/pixel +00:00:03 109MB | 85% done - 10 rays/pixel +00:00:03 109MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 8800 prims, 1 key +00:00:03 109MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 8800 prims, 1 key +00:00:03 110MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 8800 prims, 1 key +00:00:03 110MB | [accel] polymesh bvh4 done - 0:00.05 (wall time) - 8800 prims, 1 key +00:00:03 110MB | 90% done - 10 rays/pixel +00:00:03 110MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 8800 prims, 1 key +00:00:03 110MB | 95% done - 10 rays/pixel +00:00:03 110MB | 100% done - 0 rays/pixel +00:00:03 110MB | render done in 0:00.091 +00:00:03 110MB | [driver_tiff] writing file `testrender.tif' +00:00:03 110MB | render done +00:00:03 110MB | +00:00:03 110MB | ----------------------------------------------------------------------------------- +00:00:03 110MB | scene creation time 0:02.19 machine utilization (0.00%) +00:00:03 110MB | plugin loading 0:02.05 +00:00:03 110MB | unaccounted 0:00.14 +00:00:03 110MB | ----------------------------------------------------------------------------------- +00:00:03 110MB | frame time 0:01.47 machine utilization (3.21%) +00:00:03 110MB | node init 0:00.11 +00:00:03 110MB | rendering 0:00.09 +00:00:03 110MB | subdivision 0:00.01 +00:00:03 110MB | threads blocked 0:00.01 +00:00:03 110MB | threads blocked 0:00.01 +00:00:03 110MB | accel. building 0:00.05 +00:00:03 110MB | pixel rendering 0:00.01 +00:00:03 110MB | unaccounted 0:01.25 +00:00:03 110MB | ----------------------------------------------------------------------------------- +00:00:03 110MB | top session self-times by category +00:00:03 110MB | worker waiting 0:03.43 (96.07%) +00:00:03 110MB | Plugin loader 0:00.05 ( 1.43%) +00:00:03 110MB | thread blocked 0:00.04 ( 1.26%) +00:00:03 110MB | BVH::build 0:00.03 ( 0.89%) +00:00:03 110MB | TraceCameraRay 0:00.00 ( 0.09%) +00:00:03 110MB | initializeAllNodes 0:00.00 ( 0.08%) +00:00:03 110MB | ----------------------------------------------------------------------------------- +00:00:03 110MB | top session self-times by node +00:00:03 110MB | worker waiting 0:03.43 (96.07%) +00:00:03 110MB | Plugin loader 0:00.05 ( 1.43%) +00:00:03 110MB | thread blocked 0:00.04 ( 1.20%) +00:00:03 110MB | BVH::build 0:00.03 ( 0.88%) +00:00:03 110MB | usd:aiUsdShape1 0:00.00 ( 0.14%) +00:00:03 110MB | TraceCameraRay 0:00.00 ( 0.09%) +00:00:03 110MB | ----------------------------------------------------------------------------------- +00:00:03 110MB | peak CPU memory used 110.88MB +00:00:03 110MB | at startup 36.39MB +00:00:03 110MB | plugins 8.07MB +00:00:03 110MB | AOV samples 3.48MB +00:00:03 110MB | output buffers 1.08MB +00:00:03 110MB | node overhead 0.01MB +00:00:03 110MB | message passing 0.08MB +00:00:03 110MB | memory pools 30.05MB +00:00:03 110MB | geometry 2.11MB +00:00:03 110MB | polymesh 2.11MB +00:00:03 110MB | accel. structs 1.59MB +00:00:03 110MB | strings 12.00MB +00:00:03 110MB | profiler 0.03MB +00:00:03 110MB | unaccounted 15.98MB +00:00:03 110MB | ----------------------------------------------------------------------------------- +00:00:03 110MB | ray counts ( /pixel, /sample) (% total) (avg. hits) (max hits) +00:00:03 110MB | camera 192800 ( 10.04, 1.00) (100.00%) ( 0.09) ( 2) +00:00:03 110MB | total 192800 ( 10.04, 1.00) (100.00%) ( 0.09) ( 2) +00:00:03 110MB | by ray depth: 0 +00:00:03 110MB | total 100.0% +00:00:03 110MB | ----------------------------------------------------------------------------------- +00:00:03 110MB | shader calls ( /pixel, /sample) (% total) +00:00:03 110MB | primary 17124 ( 0.89, 0.09) (100.00%) +00:00:03 110MB | total 17124 ( 0.89, 0.09) (100.00%) +00:00:03 110MB | by ray depth: 0 +00:00:03 110MB | total 100.0% +00:00:03 110MB | ----------------------------------------------------------------------------------- +00:00:03 110MB | geometry (% hit ) (instances) ( init mem, final mem) +00:00:03 110MB | lists 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:03 110MB | procs 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:03 110MB | polymeshes 7 (100.0%) ( 0) ( 2.14, 2.11) +00:00:03 110MB | ----------------------------------------------------------------------------------- +00:00:03 110MB | geometric elements ( min) ( avg.) ( max) +00:00:03 110MB | objects (procs) 7 ( 7) ( 7.0) ( 7) +00:00:03 110MB | polygons 61600 ( 8800) ( 8800.0) ( 8800) +00:00:03 110MB | ----------------------------------------------------------------------------------- +00:00:03 110MB | triangle tessellation ( min) ( avg.) ( max) (/ element) (% total) +00:00:03 110MB | polymeshes 123200 ( 17600) ( 17600.0) ( 17600) ( 2.00) (100.00%) +00:00:03 110MB | unique triangles 123200 +00:00:03 110MB | CPU memory use 2.11MB +00:00:03 110MB | vertices 0.71MB +00:00:03 110MB | vertex indices 0.41MB +00:00:03 110MB | packed normals 0.24MB +00:00:03 110MB | normal indices 0.00MB +00:00:03 110MB | uv coords 0.24MB +00:00:03 110MB | uv coords idxs 0.41MB +00:00:03 110MB | uniform indices 0.10MB +00:00:03 110MB | userdata 0.00MB +00:00:03 110MB | largest polymeshes by triangle count +00:00:03 110MB | 17600 tris -- +00:00:03 110MB | 17600 tris -- +00:00:03 110MB | 17600 tris -- +00:00:03 110MB | 17600 tris -- +00:00:03 110MB | 17600 tris -- +00:00:03 110MB | ----------------------------------------------------------------------------------- +00:00:03 110MB | acceleration structures: (% total) +00:00:03 110MB | list 1 ( 11.11%) +00:00:03 110MB | bvh 8 ( 88.89%) +00:00:03 110MB | total 9 (100.00%) +00:00:03 110MB | ----------------------------------------------------------------------------------- +00:00:03 110MB | number of warnings, warning type: +00:00:03 110MB | 6: -cornerIndices + -cornerSharpnesses + -creaseIndices + -creaseLengths + -creaseSharpnesses + -doubleSided + -extent + -faceVaryingLinearInterpolation + -faceVertexCounts + -faceVertexIndices + -holeIndices + -interpolateBoundary + -normals + -orientation + -points + -primvars:displayColor + -primvars:displayOpacity + -primvars:normals + -primvars:uv + -primvars:uv:indices + -proxyPrim + -purpose + -subdivisionScheme + -triangleSubdivisionRule + -velocities + -visibility + -xformOp:transform + -xformOpOrder + +00:00:03 110MB | 1: -cornerIndices + -cornerSharpnesses + -creaseIndices + -creaseLengths + -creaseSharpnesses + -doubleSided + -extent + -faceVaryingLinearInterpolation + -faceVertexCounts + -faceVertexIndices + -holeIndices + -interpolateBoundary + -normals + -orientation + -points + -primvars:displayColor + -primvars:displayOpacity + -primvars:normals + -primvars:uv + -primvars:uv:indices + -proxyPrim + -purpose + -subdivisionScheme + -triangleSubdivisionRule + -velocities + -visibility + -xformOpOrder + +00:00:03 110MB | 1: ///////////////////////////////////////////////////////////////////Object /refSphere (type: Mesh) +00:00:03 110MB | 1: ///////////////////////////////////////////////////////////////////Object /refSphere/pCube2 (type: Mesh) +00:00:03 110MB | 1: ///////////////////////////////////////////////////////////////////Object /refSphere/pCube2/pCube5 (type: Mesh) +00:00:03 110MB | 1: ///////////////////////////////////////////////////////////////////Object /refSphere/pCube2/pCube5/pCube6 (type: Mesh) +00:00:03 110MB | 1: ///////////////////////////////////////////////////////////////////Object /refSphere/pCube3 (type: Mesh) +00:00:03 110MB | 1: ///////////////////////////////////////////////////////////////////Object /refSphere/pCube3/pCube4 (type: Mesh) +00:00:03 110MB | 1: ///////////////////////////////////////////////////////////////////Object /refSphere/pCube3/pCube4/pCube7 (type: Mesh) +00:00:03 110MB | 1: /refSphere +00:00:03 110MB | 1: /refSphere/pCube2 +00:00:03 110MB | 1: /refSphere/pCube2/pCube5 +00:00:03 110MB | 1: /refSphere/pCube2/pCube5/pCube6 +00:00:03 110MB | 1: /refSphere/pCube3 +00:00:03 110MB | 1: /refSphere/pCube3/pCube4 +00:00:03 110MB | 1: /refSphere/pCube3/pCube4/pCube7 +00:00:03 110MB | 1: ==== Initializing procedural aiUsdShape1 +00:00:03 110MB | 7: =============== A +00:00:03 110MB | 7: =============== EXPORTING MEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEESG +00:00:03 110MB | 7: =============== EXPORTed vidx +00:00:03 110MB | 7: =============== EXPORTed vlist +00:00:03 110MB | 7: =============== PUSHING NODE +00:00:03 110MB | 7: =============== voilaaaaa +00:00:03 110MB | 7: [usd] %s subdivision scheme not supported for mesh on path %s +00:00:03 110MB | 4: unable to load dynamic library %s: %s +00:00:03 110MB | ----------------------------------------------------------------------------------- +00:00:03 110MB | performance warnings: +00:00:03 110MB WARNING | Rendering utilization was only 3%. Your render may be bound by a single threaded process or I/O. +00:00:03 110MB WARNING | Scene creation was a significant amount of total time (60%). Consider optimizing this process first. +00:00:03 110MB | ----------------------------------------------------------------------------------- +00:00:03 105MB | +00:00:03 105MB | releasing resources +00:00:03 88MB | unloading 5 plugins +00:00:03 88MB | closing mtoa_ParticleInstancer_proc.dll ... +00:00:03 88MB | closing mtoa_ParticleVolume_proc.dll ... +00:00:03 88MB | closing usd_proc.dll ... +00:00:03 87MB | closing alembic_proc.dll ... +00:00:03 87MB | closing cryptomatte.dll ... +00:00:03 87MB | unloading plugins done +00:00:03 87MB | Arnold shutdown diff --git a/testsuite/test_0011/ref/reference.tif b/testsuite/test_0011/ref/reference.tif new file mode 100755 index 0000000000..7c6d1c88c9 Binary files /dev/null and b/testsuite/test_0011/ref/reference.tif differ diff --git a/testsuite/test_0012/README b/testsuite/test_0012/README new file mode 100755 index 0000000000..d4c0b988a7 --- /dev/null +++ b/testsuite/test_0012/README @@ -0,0 +1,3 @@ +USD references using sublayers + +author: sebastien ortega diff --git a/testsuite/test_0012/data/asset.usda b/testsuite/test_0012/data/asset.usda new file mode 100755 index 0000000000..f3b9dc33b1 --- /dev/null +++ b/testsuite/test_0012/data/asset.usda @@ -0,0 +1,42 @@ +#usda 1.0 +def Xform "root" +{ +def Cube "cube" +{ + double size=2 + float3 xformOp:translate= (4.8,0, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] +} +def Sphere "sphere" +{ + double radius=1.8 + float3 xformOp:translate= (-4.8,0, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] +} + +def Cylinder "cylinder" +{ + double radius=1.1 + double height=3 + token axis="Y" + float3 xformOp:translate= (0,0, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] +} + +def Cone "cone" +{ + double radius=1.6 + double height=2.7 + token axis="X" + float3 xformOp:translate= (0,5, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] +} +def Capsule "capsule" +{ + double radius=1.6 + double height=2.7 + token axis="X" + float3 xformOp:translate= (4,5, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] +} +} \ No newline at end of file diff --git a/testsuite/test_0012/data/shot.usda b/testsuite/test_0012/data/shot.usda new file mode 100755 index 0000000000..fc4e0c6b99 --- /dev/null +++ b/testsuite/test_0012/data/shot.usda @@ -0,0 +1,4 @@ +#usda 1.0 +( +subLayers = [@./asset.usda@] +) \ No newline at end of file diff --git a/testsuite/test_0012/data/test.ass b/testsuite/test_0012/data/test.ass new file mode 100755 index 0000000000..9106cc69a4 --- /dev/null +++ b/testsuite/test_0012/data/test.ass @@ -0,0 +1,110 @@ +### exported: Tue Dec 18 15:45:58 2018 +### from: Arnold 5.2.2.0 [30b8ba14] windows icc-17.0.2 oiio-2.0.1 osl-1.10.1 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 2018/12/04 22:02:04 +### host app: MtoA 3.1.3.wip 7d48f6c4 (develop) Maya 2018 +### bounds: -1 -1 -1 1 1 1 +### user: blaines +### render_layer: defaultRenderLayer +### scene: D:/arnold/scenes/usd_builtin.ma + + + +options +{ + AA_samples 3 + AA_samples_max 8 + outputs "RGBA RGBA myfilter mydriver" + xres 960 + yres 540 + texture_per_file_stats on + texture_automip off + camera "perspShape" + frame 1 + GI_diffuse_depth 1 + GI_specular_depth 1 + GI_transmission_depth 8 + declare render_layer constant STRING + render_layer "defaultRenderLayer" +} + +gaussian_filter +{ + name myfilter +} + +driver_tiff +{ + name mydriver + filename "testrender.tif" + color_space "sRGB" +} + +persp_camera +{ + name perspShape + matrix + 0.99999392 -1.08420217e-19 0.00349065149 0 + 0.000781565788 0.974611521 -0.223901182 0 + -0.00340202916 0.223902553 0.97460562 0 + -0.949623287 7.26941013 21.0998859 1 + near_clip 0.100000001 + far_clip 10000 + screen_window_min -1 -1 + screen_window_max 1 1 + shutter_start 0 + shutter_end 0 + shutter_type "box" + rolling_shutter "off" + rolling_shutter_duration 0 + motion_start 0 + motion_end 0 + exposure 0 + fov 34.4322243 + uv_remap 0 0 0 1 + declare maya_full_name constant STRING + maya_full_name "|persp|perspShape" +} + +distant_light +{ + name directionalLightShape1 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 0 0 1 + exposure 0 + cast_shadows on + cast_volumetric_shadows on + shadow_density 1 + samples 1 + normalize on + diffuse 1 + specular 1 + sss 1 + indirect 1 + max_bounces 999 + volume_samples 2 + volume 1 + aov "default" + angle 0 + declare maya_full_name constant STRING + maya_full_name "|directionalLight1|directionalLightShape1" +} + +usd +{ + name aiUsdShape1 + visibility 255 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 0 0 1 + use_light_group off + override_nodes off + filename "shot.usda" + frame 1 + declare maya_full_name constant STRING + maya_full_name "|aiUsd1|aiUsdShape1" +} + diff --git a/testsuite/test_0012/ref/reference.log b/testsuite/test_0012/ref/reference.log new file mode 100755 index 0000000000..e0b12e722a --- /dev/null +++ b/testsuite/test_0012/ref/reference.log @@ -0,0 +1,322 @@ +00:00:02 61MB | log started Thu Dec 27 19:11:12 2018 +00:00:02 61MB | Arnold 5.2.2.0 [62163448] windows icc-17.0.2 oiio-2.0.1 osl-1.10.1 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 2018/12/04 03:55:51 +00:00:02 61MB | running on REM8WCK8D2, pid=19048 +00:00:02 61MB | 2 x Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz (20 cores, 40 logical) with 65458MB +00:00:02 61MB | Nvidia driver version 391.03 +00:00:02 61MB | GPU 0: Quadro K620 @ 1124MHz (compute 5.0) with 2048MB (1477MB available) +00:00:02 61MB | Windows 7 Enterprise Edition Service Pack 1 (version 6.1, build 7601) +00:00:02 61MB | soft limit for open files raised from 512 to 2048 +00:00:02 61MB | +00:00:02 61MB | loading plugins from C:\solidangle\mtoadeploy\2018\procedurals ... +00:00:02 61MB | mtoa_ParticleInstancer_proc.dll: particleInstancer uses Arnold 5.2.2.0 +00:00:02 61MB | mtoa_ParticleVolume_proc.dll: volume_particle uses Arnold 5.2.2.0 +00:00:02 61MB | mtoa_ParticleVolume_proc.dll: implicit_particle uses Arnold 5.2.2.0 +00:00:02 61MB | usd_proc.dll: usd uses Arnold 5.2.2.0 +00:00:02 61MB | [metadata] loading metadata file: C:\solidangle\mtoadeploy\2018\procedurals\usd_proc.mtd +00:00:02 61MB WARNING | unable to load dynamic library C:\solidangle\mtoadeploy\2018\procedurals\xgenSpline_procedural.dll: The specified module could not be found. + + +00:00:02 61MB WARNING | unable to load dynamic library C:\solidangle\mtoadeploy\2018\procedurals\xgen_procedural.dll: The specified module could not be found. + + +00:00:02 61MB | loaded 4 plugins from 3 lib(s) in 0:01.88 +00:00:02 61MB | loading plugins from D:\arnold\releases\Arnold_latest-windows\bin\..\plugins ... +00:00:02 61MB | alembic_proc.dll: alembic uses Arnold 5.2.2.0 +00:00:02 61MB | cryptomatte.dll: cryptomatte uses Arnold 5.2.2.0 +00:00:02 61MB | cryptomatte.dll: cryptomatte_filter uses Arnold 5.2.2.0 +00:00:02 61MB | cryptomatte.dll: cryptomatte_manifest_driver uses Arnold 5.2.2.0 +00:00:02 61MB | loaded 4 plugins from 2 lib(s) in 0:00.00 +00:00:02 61MB | [kick] command: D:\arnold\releases\Arnold_latest-windows\bin\kick test.ass -dw -r 160 120 -bs 16 -o testrender.tif -set driver_tiff.dither false -nocrashpopup -dp -v 6 -l C:\solidangle\mtoadeploy\2018\procedurals +00:00:02 61MB | loading plugins from C:\solidangle\mtoadeploy\2018\procedurals ... +00:00:02 61MB WARNING | unable to load dynamic library C:\solidangle\mtoadeploy\2018\procedurals\xgenSpline_procedural.dll: The specified module could not be found. + + +00:00:02 61MB WARNING | unable to load dynamic library C:\solidangle\mtoadeploy\2018\procedurals\xgen_procedural.dll: The specified module could not be found. + + +00:00:02 61MB | no plugins loaded +00:00:02 61MB | loading plugins from . ... +00:00:02 61MB | no plugins loaded +00:00:02 61MB | [metadata] loading metadata file: test.ass +00:00:02 61MB | [ass] loading test.ass ... +00:00:02 61MB | [ass] read 2109 bytes, 6 nodes in 0:00.00 +00:00:02 61MB | [kick] applying 1 attr value override +00:00:02 61MB | +00:00:02 62MB | authorizing with default license managers: rlm, clm ... +00:00:03 69MB | [clm] authorized for "86985ARNOL_2018_0F" in 0:01.35 +00:00:03 69MB | [clm] expiration date: permanent, in use: 1/100 +00:00:03 69MB | +00:00:03 69MB | [color_manager] no color manager is active +00:00:03 69MB | [color_manager] rendering color space is "linear" with declared chromaticities: +00:00:03 69MB | r(0.6400, 0.3300) g(0.3000, 0.6000) b(0.1500, 0.0600) and w(0.3127, 0.3290) +00:00:03 80MB | +00:00:03 80MB | there are 1 light and 2 objects: +00:00:03 80MB | 1 persp_camera +00:00:03 80MB | 1 distant_light +00:00:03 80MB | 1 utility +00:00:03 80MB | 1 driver_tiff +00:00:03 80MB | 1 gaussian_filter +00:00:03 80MB | 1 list_aggregate +00:00:03 80MB | 1 usd +00:00:03 80MB | +00:00:03 80MB | rendering image at 160 x 120, 3 AA samples +00:00:03 80MB | AA samples max +00:00:03 80MB | AA sample clamp +00:00:03 80MB | diffuse samples 2 / depth 1 +00:00:03 80MB | specular samples 2 / depth 1 +00:00:03 80MB | transmission samples 2 / depth 8 +00:00:03 80MB | volume indirect +00:00:03 80MB | total depth 10 +00:00:03 80MB | bssrdf samples 2 +00:00:03 80MB | transparency depth 10 +00:00:03 80MB | initializing 8 nodes ... +00:00:03 92MB WARNING | ==== Initializing procedural aiUsdShape1 +00:00:03 92MB WARNING | Object /refSphere (type: Xform) +00:00:03 92MB WARNING | -proxyPrim + -purpose + -visibility + -xformOpOrder + +00:00:03 92MB WARNING | Object /refSphere/cube (type: Cube) +00:00:03 92MB WARNING | -doubleSided + -extent + -orientation + -primvars:displayColor + -primvars:displayOpacity + -proxyPrim + -purpose + -size + -visibility + -xformOp:translate + -xformOpOrder + +00:00:03 92MB WARNING | Object /refSphere/sphere (type: Sphere) +00:00:03 92MB WARNING | -doubleSided + -extent + -orientation + -primvars:displayColor + -primvars:displayOpacity + -proxyPrim + -purpose + -radius + -visibility + -xformOp:translate + -xformOpOrder + +00:00:03 92MB WARNING | Object /refSphere/cylinder (type: Cylinder) +00:00:03 92MB WARNING | -axis + -doubleSided + -extent + -height + -orientation + -primvars:displayColor + -primvars:displayOpacity + -proxyPrim + -purpose + -radius + -visibility + -xformOp:translate + -xformOpOrder + +00:00:03 92MB WARNING | Object /refSphere/cone (type: Cone) +00:00:03 92MB WARNING | -axis + -doubleSided + -extent + -height + -orientation + -primvars:displayColor + -primvars:displayOpacity + -proxyPrim + -purpose + -radius + -visibility + -xformOp:translate + -xformOpOrder + +00:00:03 92MB WARNING | Object /refSphere/capsule (type: Capsule) +00:00:03 92MB WARNING | -axis + -doubleSided + -extent + -height + -orientation + -primvars:displayColor + -primvars:displayOpacity + -proxyPrim + -purpose + -radius + -visibility + -xformOp:translate + -xformOpOrder + +00:00:03 92MB | [proc] aiUsdShape1: loaded 5 nodes (5 objects, 0 shaders) +00:00:03 92MB | creating root object list ... +00:00:03 92MB | node initialization done in 0:00.10 (multithreaded) +00:00:03 92MB | updating 14 nodes ... +00:00:03 93MB | directionalLightShape1: distant_light using 1 sample, 2 volume samples +00:00:03 93MB | scene bounds: (-6.60000038 -1.79999995 -1.79999995) -> (5.80000019 6.60000086 1.79999995) +00:00:03 93MB | node update done in 0:00.00 (multithreaded) +00:00:03 93MB | [aov] parsing 1 output statements ... +00:00:03 93MB | [aov] registered driver: "mydriver" (driver_tiff) +00:00:03 93MB | [aov] * "RGBA" of type RGBA filtered by "myfilter" (gaussian_filter) +00:00:03 93MB | [aov] done preparing 2 AOVs for 1 output to 1 driver (0 deep AOVs) +00:00:03 93MB | starting 40 bucket workers of size 16x16 ... +00:00:03 100MB | [accel] procedural bvh4 done - 0:00.00 (wall time) - 5 prims, 1 key +00:00:03 100MB | 0% done - 10 rays/pixel +00:00:03 100MB | 5% done - 10 rays/pixel +00:00:03 100MB | 10% done - 10 rays/pixel +00:00:03 100MB | 15% done - 10 rays/pixel +00:00:03 100MB | 20% done - 10 rays/pixel +00:00:03 100MB | 25% done - 10 rays/pixel +00:00:03 100MB | 30% done - 10 rays/pixel +00:00:03 100MB | 35% done - 10 rays/pixel +00:00:03 101MB | 40% done - 10 rays/pixel +00:00:03 101MB | 45% done - 10 rays/pixel +00:00:03 101MB | 50% done - 10 rays/pixel +00:00:03 101MB | 55% done - 10 rays/pixel +00:00:03 101MB | 60% done - 10 rays/pixel +00:00:03 101MB | 65% done - 10 rays/pixel +00:00:03 101MB | 70% done - 10 rays/pixel +00:00:03 101MB | 75% done - 11 rays/pixel +00:00:03 101MB | 80% done - 0 rays/pixel +00:00:03 101MB | 85% done - 0 rays/pixel +00:00:03 101MB | 90% done - 0 rays/pixel +00:00:03 101MB | 95% done - 0 rays/pixel +00:00:03 101MB | 100% done - 0 rays/pixel +00:00:03 101MB | render done in 0:00.013 +00:00:03 101MB | [driver_tiff] writing file `testrender.tif' +00:00:03 101MB | render done +00:00:03 101MB | +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | scene creation time 0:02.42 machine utilization (0.08%) +00:00:03 101MB | plugin loading 0:02.29 +00:00:03 101MB | unaccounted 0:00.12 +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | frame time 0:01.50 machine utilization (4.50%) +00:00:03 101MB | node init 0:00.10 +00:00:03 101MB | driver init/close 0:00.01 +00:00:03 101MB | rendering 0:00.01 +00:00:03 101MB | pixel rendering 0:00.01 +00:00:03 101MB | unaccounted 0:01.37 +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | top session self-times by category +00:00:03 101MB | worker waiting 0:03.78 (98.14%) +00:00:03 101MB | Plugin loader 0:00.05 ( 1.49%) +00:00:03 101MB | thread blocked 0:00.00 ( 0.09%) +00:00:03 101MB | node_init (aiUsdShape1) 0:00.00 ( 0.07%) +00:00:03 101MB | initializeAllNodes 0:00.00 ( 0.07%) +00:00:03 101MB | TraceCameraRay 0:00.00 ( 0.05%) +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | top session self-times by node +00:00:03 101MB | worker waiting 0:03.78 (98.14%) +00:00:03 101MB | Plugin loader 0:00.05 ( 1.49%) +00:00:03 101MB | usd:aiUsdShape1 0:00.00 ( 0.12%) +00:00:03 101MB | initializeAllNodes 0:00.00 ( 0.07%) +00:00:03 101MB | thread blocked 0:00.00 ( 0.07%) +00:00:03 101MB | TraceCameraRay 0:00.00 ( 0.05%) +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | peak CPU memory used 101.54MB +00:00:03 101MB | at startup 36.43MB +00:00:03 101MB | plugins 8.05MB +00:00:03 101MB | AOV samples 3.48MB +00:00:03 101MB | output buffers 1.08MB +00:00:03 101MB | node overhead 0.00MB +00:00:03 101MB | message passing 0.08MB +00:00:03 101MB | memory pools 30.05MB +00:00:03 101MB | geometry 0.00MB +00:00:03 101MB | accel. structs 0.01MB +00:00:03 101MB | strings 12.00MB +00:00:03 101MB | profiler 0.01MB +00:00:03 101MB | unaccounted 10.35MB +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | ray counts ( /pixel, /sample) (% total) (avg. hits) (max hits) +00:00:03 101MB | camera 192800 ( 10.04, 1.00) (100.00%) ( 0.28) ( 1) +00:00:03 101MB | total 192800 ( 10.04, 1.00) (100.00%) ( 0.28) ( 1) +00:00:03 101MB | by ray depth: 0 +00:00:03 101MB | total 100.0% +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | shader calls ( /pixel, /sample) (% total) +00:00:03 101MB | primary 54714 ( 2.85, 0.28) (100.00%) +00:00:03 101MB | total 54714 ( 2.85, 0.28) (100.00%) +00:00:03 101MB | by ray depth: 0 +00:00:03 101MB | total 100.0% +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | geometry (% hit ) (instances) ( init mem, final mem) +00:00:03 101MB | lists 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:03 101MB | procs 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:03 101MB | simple 5 (100.0%) ( 0) ( 0.00, 0.00) +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | geometric elements ( min) ( avg.) ( max) +00:00:03 101MB | objects (procs) 5 ( 5) ( 5.0) ( 5) +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | acceleration structures: (% total) +00:00:03 101MB | list 1 ( 50.00%) +00:00:03 101MB | bvh 1 ( 50.00%) +00:00:03 101MB | total 2 (100.00%) +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | number of warnings, warning type: +00:00:03 101MB | 3: -axis + -doubleSided + -extent + -height + -orientation + -primvars:displayColor + -primvars:displayOpacity + -proxyPrim + -purpose + -radius + -visibility + -xformOp:translate + -xformOpOrder + +00:00:03 101MB | 1: -doubleSided + -extent + -orientation + -primvars:displayColor + -primvars:displayOpacity + -proxyPrim + -purpose + -radius + -visibility + -xformOp:translate + -xformOpOrder + +00:00:03 101MB | 1: -doubleSided + -extent + -orientation + -primvars:displayColor + -primvars:displayOpacity + -proxyPrim + -purpose + -size + -visibility + -xformOp:translate + -xformOpOrder + +00:00:03 101MB | 1: -proxyPrim + -purpose + -visibility + -xformOpOrder + +00:00:03 101MB | 1: ==== Initializing procedural aiUsdShape1 +00:00:03 101MB | 1: Object /refSphere (type: Xform) +00:00:03 101MB | 1: Object /refSphere/capsule (type: Capsule) +00:00:03 101MB | 1: Object /refSphere/cone (type: Cone) +00:00:03 101MB | 1: Object /refSphere/cube (type: Cube) +00:00:03 101MB | 1: Object /refSphere/cylinder (type: Cylinder) +00:00:03 101MB | 1: Object /refSphere/sphere (type: Sphere) +00:00:03 101MB | 4: unable to load dynamic library %s: %s +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | performance warnings: +00:00:03 101MB WARNING | Rendering utilization was only 5%. Your render may be bound by a single threaded process or I/O. +00:00:03 101MB WARNING | Scene creation was a significant amount of total time (62%). Consider optimizing this process first. +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 96MB | +00:00:03 96MB | releasing resources +00:00:04 83MB | unloading 5 plugins +00:00:04 83MB | closing mtoa_ParticleInstancer_proc.dll ... +00:00:04 83MB | closing mtoa_ParticleVolume_proc.dll ... +00:00:04 83MB | closing usd_proc.dll ... +00:00:04 82MB | closing alembic_proc.dll ... +00:00:04 82MB | closing cryptomatte.dll ... +00:00:04 82MB | unloading plugins done +00:00:04 82MB | Arnold shutdown diff --git a/testsuite/test_0012/ref/reference.tif b/testsuite/test_0012/ref/reference.tif new file mode 100755 index 0000000000..815078766a Binary files /dev/null and b/testsuite/test_0012/ref/reference.tif differ diff --git a/testsuite/test_0013/README b/testsuite/test_0013/README new file mode 100755 index 0000000000..0d2ad80827 --- /dev/null +++ b/testsuite/test_0013/README @@ -0,0 +1,6 @@ +Test USD Native shaders + +See trac#7814 + +author: sebastien ortega + diff --git a/testsuite/test_0013/data/builtin_shapes.usda b/testsuite/test_0013/data/builtin_shapes.usda new file mode 100755 index 0000000000..27268735e7 --- /dev/null +++ b/testsuite/test_0013/data/builtin_shapes.usda @@ -0,0 +1,23 @@ +#usda 1.0 +( + defaultPrim = "cube" +) + + +def Cylinder "cylinder" +{ + double radius=1.1 + double height=3 + token axis="Y" + float3 xformOp:translate= (0,0, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] +} + +def Cone "cone" +{ + double radius=1.6 + double height=2.7 + token axis="X" + float3 xformOp:translate= (0,5, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] +} diff --git a/testsuite/test_0013/data/mat_jpg.jpg b/testsuite/test_0013/data/mat_jpg.jpg new file mode 100755 index 0000000000..7d8e44ce54 Binary files /dev/null and b/testsuite/test_0013/data/mat_jpg.jpg differ diff --git a/testsuite/test_0013/data/mat_png.png b/testsuite/test_0013/data/mat_png.png new file mode 100755 index 0000000000..9a001cc780 Binary files /dev/null and b/testsuite/test_0013/data/mat_png.png differ diff --git a/testsuite/test_0013/data/shading.usda b/testsuite/test_0013/data/shading.usda new file mode 100755 index 0000000000..cfc888b3d2 --- /dev/null +++ b/testsuite/test_0013/data/shading.usda @@ -0,0 +1,49 @@ +#usda 1.0 + +def "World" +{ + def Material "material" + { + def NodeGraph "nodeGraph" + { + def Shader "PreviewShader" + { + uniform token info:id = "UsdPreviewSurface" + color3f inputs:diffuseColor.connect = + + } + def Shader "PrimvarSt1" + { + uniform token info:id = "UsdPrimvarReader_float2" + } + } + def Shader "SecondPreviewShader" + { + uniform token info:id = "UsdPreviewSurface" + color3f inputs:diffuseColor = (1,0,0) + } + def Shader "pngTex" + { + uniform token info:id = "UsdUVTexture" + asset inputs:file = @mat_png.png@ + color3f outputs:rgb + } + + def Shader "jpgTex" + { + uniform token info:id = "UsdUVTexture" + asset inputs:file = @mat_jpg.jpg@ + } + + def Shader "PrimvarSt" + { + uniform token info:id = "UsdPrimvarReader_float2" + } + + def Shader "PrimvarOcclusion" + { + uniform token info:id = "UsdPrimvarReader_float" + } + } +} + diff --git a/testsuite/test_0013/data/test.ass b/testsuite/test_0013/data/test.ass new file mode 100755 index 0000000000..299b7e41c9 --- /dev/null +++ b/testsuite/test_0013/data/test.ass @@ -0,0 +1,133 @@ +### exported: Tue Dec 18 15:45:58 2018 +### from: Arnold 5.2.2.0 [30b8ba14] windows icc-17.0.2 oiio-2.0.1 osl-1.10.1 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 2018/12/04 22:02:04 +### host app: MtoA 3.1.3.wip 7d48f6c4 (develop) Maya 2018 +### bounds: -1 -1 -1 1 1 1 +### user: blaines +### render_layer: defaultRenderLayer +### scene: D:/arnold/scenes/usd_builtin.ma + + + +options +{ + AA_samples 3 + AA_samples_max 8 + outputs "RGBA RGBA myfilter mydriver" + xres 960 + yres 540 + texture_per_file_stats on + texture_automip off + camera "perspShape" + frame 1 + GI_diffuse_depth 1 + GI_specular_depth 1 + GI_transmission_depth 8 + operator "root_op" + declare render_layer constant STRING + render_layer "defaultRenderLayer" + parallel_node_init off +} + +gaussian_filter +{ + name myfilter +} + +driver_tiff +{ + name mydriver + filename "testrender.tif" + color_space "sRGB" +} + +persp_camera +{ + name perspShape + matrix + 0.99999392 -1.08420217e-19 0.00349065149 0 + 0.000781565788 0.974611521 -0.223901182 0 + -0.00340202916 0.223902553 0.97460562 0 + -0.949623287 7.26941013 21.0998859 1 + near_clip 0.100000001 + far_clip 10000 + screen_window_min -1 -1 + screen_window_max 1 1 + shutter_start 0 + shutter_end 0 + shutter_type "box" + rolling_shutter "off" + rolling_shutter_duration 0 + motion_start 0 + motion_end 0 + exposure 0 + fov 34.4322243 + uv_remap 0 0 0 1 + declare maya_full_name constant STRING + maya_full_name "|persp|perspShape" +} + +distant_light +{ + name directionalLightShape1 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 0 0 1 + exposure 0 + cast_shadows on + cast_volumetric_shadows on + shadow_density 1 + samples 1 + normalize on + diffuse 1 + specular 1 + sss 1 + indirect 1 + max_bounces 999 + volume_samples 2 + volume 1 + aov "default" + angle 0 + declare maya_full_name constant STRING + maya_full_name "|directionalLight1|directionalLightShape1" +} + +usd +{ + name aiUsdShape + visibility 255 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 0 0 1 + use_light_group off + override_nodes off + filename "builtin_shapes.usda" + frame 1 + declare maya_full_name constant STRING + maya_full_name "|aiUsd1|aiUsdShape1" +} + + +usd +{ + name aiUsdShaders + visibility 255 + filename "shading.usda" +} + +set_parameter +{ + name root_op + selection "aiUsdShape/cylinder" + assignment "shader=\"^aiUsdShaders^/World/material/SecondPreviewShader\"" + inputs second_op +} +set_parameter +{ + name second_op + selection "aiUsdShape/cone" + assignment "shader=\"^aiUsdShaders^/World/material/nodeGraph/PreviewShader\"" +} diff --git a/testsuite/test_0013/ref/reference.log b/testsuite/test_0013/ref/reference.log new file mode 100755 index 0000000000..190fabeda0 --- /dev/null +++ b/testsuite/test_0013/ref/reference.log @@ -0,0 +1,235 @@ +00:00:00 61MB | log started Fri May 17 09:25:43 2019 +00:00:00 61MB | Arnold 5.3.0.0 [b452526e] windows icc-17.0.2 oiio-2.1.0 osl-1.11.0 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 optix-6.0.0 2019/03/20 01:03:22 +00:00:00 61MB | running on REM8WCK8D2, pid=10236 +00:00:00 61MB | 2 x Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz (20 cores, 40 logical) with 65456MB +00:00:00 61MB | NVIDIA driver version 430.64 +00:00:00 61MB | GPU 0: GeForce RTX 2080 Ti @ 1635MHz (compute 7.5) with 11264MB (10990MB available) (NVLink:0) +00:00:00 61MB | GPU 1: Quadro K620 @ 1124MHz (compute 5.0) with 2048MB (1598MB available) (NVLink:0) +00:00:00 61MB | Windows 7 Enterprise Edition Service Pack 1 (version 6.1, build 7601) +00:00:00 61MB | soft limit for open files raised from 512 to 2048 +00:00:00 61MB | +00:00:00 61MB | loading plugins from D:\arnold\usd_procedural\build\windows_x86_64\msvc_opt\usd-0.18.11_arnold-5.3.0.0\procedural ... +00:00:00 61MB | usd_proc.dll: usd uses Arnold 5.3.0.0 +00:00:00 61MB | loaded 1 plugins from 1 lib(s) in 0:00.07 +00:00:00 61MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\bin\..\plugins ... +00:00:00 61MB | no plugins loaded +00:00:00 61MB | [kick] command: D:\arnold\releases\Arnold_latest-windows-usd\bin\kick test.ass -dw -r 160 120 -bs 16 -o testrender.tif -set driver_tiff.dither false -nocrashpopup -dp -v 6 +00:00:00 61MB | loading plugins from . ... +00:00:00 61MB | no plugins loaded +00:00:00 61MB | [metadata] loading metadata file: test.ass +00:00:00 62MB | [ass] loading test.ass ... +00:00:00 62MB | [ass] read 2544 bytes, 9 nodes in 0:00.00 +00:00:00 62MB | [kick] applying 1 attr value override +00:00:00 62MB | +00:00:00 62MB | authorizing with default license managers: rlm, clm ... +00:00:02 70MB | [clm] authorized for "86985ARNOL_2018_0F" in 0:02.50 +00:00:02 70MB | [clm] expiration date: permanent, in use: 1/1000 +00:00:02 70MB | +00:00:02 70MB | [color_manager] no color manager is active +00:00:02 70MB | [color_manager] rendering color space is "linear" with declared chromaticities: +00:00:02 70MB | r(0.6400, 0.3300) g(0.3000, 0.6000) b(0.1500, 0.0600) and w(0.3127, 0.3290) +00:00:02 81MB | +00:00:02 81MB | there are 1 light and 3 objects: +00:00:02 81MB | 1 persp_camera +00:00:02 81MB | 1 distant_light +00:00:02 81MB | 1 utility +00:00:02 81MB | 1 driver_tiff +00:00:02 81MB | 1 gaussian_filter +00:00:02 81MB | 1 list_aggregate +00:00:02 81MB | 2 set_parameter +00:00:02 81MB | 2 usd +00:00:02 81MB | +00:00:02 81MB | rendering image at 160 x 120, 3 AA samples +00:00:02 81MB | AA samples max +00:00:02 81MB | AA sample clamp +00:00:02 81MB | diffuse samples 2 / depth 1 +00:00:02 81MB | specular samples 2 / depth 1 +00:00:02 81MB | transmission samples 2 / depth 8 +00:00:02 81MB | volume indirect +00:00:02 81MB | total depth 10 +00:00:02 81MB | bssrdf samples 2 +00:00:02 81MB | transparency depth 10 +00:00:02 81MB | initializing 11 nodes ... +00:00:02 94MB | [proc] aiUsdShape: loaded 2 nodes (2 objects, 0 shaders) +==== READ /World/material/nodeGraph/PreviewShader create=1, convert=1 +==== READ /World/material/pngTex create=1, convert=0 +00:00:02 94MB WARNING | /World/material/nodeGraph/PreviewShader: could not set FLOAT parameter " specular_IOR " +00:00:02 94MB WARNING | /World/material/nodeGraph/PreviewShader.opacity: use type RGB, not FLOAT +00:00:02 94MB WARNING | /World/material/nodeGraph/PreviewShader: could not set FLOAT parameter "opacity" +==== READ /World/material/nodeGraph/PrimvarSt1 create=1, convert=1 +==== READ /World/material/SecondPreviewShader create=1, convert=1 +00:00:02 94MB WARNING | /World/material/SecondPreviewShader: could not set FLOAT parameter " specular_IOR " +00:00:02 94MB WARNING | /World/material/SecondPreviewShader.opacity: use type RGB, not FLOAT +00:00:02 94MB WARNING | /World/material/SecondPreviewShader: could not set FLOAT parameter "opacity" +==== READ /World/material/pngTex create=1, convert=1 +==== READ /World/material/jpgTex create=1, convert=1 +==== READ /World/material/PrimvarSt create=1, convert=1 +==== READ /World/material/PrimvarOcclusion create=1, convert=1 +00:00:02 94MB | [proc] aiUsdShaders: loaded 7 nodes (0 objects, 7 shaders) +00:00:02 94MB | [operators] init op: 'root_op' +00:00:02 94MB | [operators] cook op: 'root_op' | node: 'aiUsdShape/cylinder' +00:00:02 94MB | [operators] init op: 'second_op' +00:00:02 94MB | [operators] cook op: 'second_op' | node: 'aiUsdShape/cone' +00:00:02 94MB | creating root object list ... +00:00:02 94MB | node initialization done in 0:00.04 (single-threaded) +00:00:02 94MB | [operators] post cook op: 'second_op' +00:00:02 94MB | [operators] post cook op: 'root_op' +00:00:02 94MB | updating 21 nodes ... +00:00:02 94MB | directionalLightShape1: distant_light using 1 sample, 2 volume samples +00:00:02 94MB | scene bounds: (-2.95000005 -1.5 -1.60000002) -> (1.35000002 6.5999999 1.60000002) +00:00:02 94MB | node update done in 0:00.00 (single-threaded) +00:00:02 94MB | [aov] parsing 1 output statements ... +00:00:02 94MB | [aov] registered driver: "mydriver" (driver_tiff) +00:00:02 94MB | [aov] * "RGBA" of type RGBA filtered by "myfilter" (gaussian_filter) +00:00:02 94MB | [aov] done preparing 2 AOVs for 1 output to 1 driver (0 deep AOVs) +00:00:02 95MB | starting 40 bucket workers of size 16x16 ... +00:00:02 98MB | [accel] procedural bvh4 done - 0:00.00 (wall time) - 2 prims, 1 key +00:00:02 99MB | 0% done - 8 rays/pixel +00:00:02 100MB | 5% done - 5 rays/pixel +00:00:02 100MB | 10% done - 12 rays/pixel +00:00:02 101MB | 15% done - 4 rays/pixel +00:00:02 102MB | 20% done - 22 rays/pixel +00:00:02 103MB | 25% done - 15 rays/pixel +00:00:02 103MB | 30% done - 8 rays/pixel +00:00:02 104MB | 35% done - 0 rays/pixel +00:00:02 104MB | 40% done - 10 rays/pixel +00:00:02 104MB | 45% done - 21 rays/pixel +00:00:02 104MB | 50% done - 13 rays/pixel +00:00:02 104MB | 55% done - 23 rays/pixel +00:00:02 104MB | 60% done - 12 rays/pixel +00:00:02 105MB | 65% done - 36 rays/pixel +00:00:02 105MB | 70% done - 197 rays/pixel +00:00:02 105MB | 75% done - 114 rays/pixel +00:00:02 105MB | 80% done - 0 rays/pixel +00:00:02 105MB | 85% done - 0 rays/pixel +00:00:02 105MB | 90% done - 0 rays/pixel +00:00:02 105MB | 95% done - 0 rays/pixel +00:00:02 106MB | 100% done - 0 rays/pixel +00:00:02 106MB | render done in 0:00.055 +00:00:02 106MB | [driver_tiff] writing file `testrender.tif' +00:00:02 106MB | render done +00:00:02 106MB | +00:00:02 106MB | ----------------------------------------------------------------------------------- +00:00:02 106MB | scene creation time 0:00.29 machine utilization (0.13%) +00:00:02 106MB | plugin loading 0:00.08 +00:00:02 106MB | unaccounted 0:00.21 +00:00:02 106MB | ----------------------------------------------------------------------------------- +00:00:02 106MB | frame time 0:02.63 machine utilization (1.37%) +00:00:02 106MB | node init 0:00.04 +00:00:02 106MB | rendering 0:00.05 +00:00:02 106MB | pixel rendering 0:00.05 +00:00:02 106MB | unaccounted 0:02.53 +00:00:02 106MB | ----------------------------------------------------------------------------------- +00:00:02 106MB | top session self-times by category +00:00:02 106MB | worker waiting 0:02.66 (99.20%) +00:00:02 106MB | thread blocked 0:00.00 ( 0.14%) +00:00:02 106MB | AiTextureHandleAccess 0:00.00 ( 0.13%) +00:00:02 106MB | surface closure 0:00.00 ( 0.10%) +00:00:02 106MB | Plugin loader 0:00.00 ( 0.08%) +00:00:02 106MB | TraceCameraRay 0:00.00 ( 0.07%) +00:00:02 106MB | ----------------------------------------------------------------------------------- +00:00:02 106MB | top session self-times by node +00:00:02 106MB | worker waiting 0:02.66 (99.20%) +00:00:02 106MB | thread blocked 0:00.00 ( 0.14%) +00:00:02 106MB | image:/World/material/pngTex 0:00.00 ( 0.13%) +00:00:02 106MB | standard_surface:/World/material/SecondPreviewShader 0:00.00 ( 0.11%) +00:00:02 106MB | usd:aiUsdShape 0:00.00 ( 0.09%) +00:00:02 106MB | Plugin loader 0:00.00 ( 0.08%) +00:00:02 106MB | ----------------------------------------------------------------------------------- +00:00:02 106MB | peak CPU memory used 106.61MB +00:00:02 106MB | at startup 36.85MB +00:00:02 106MB | plugins 6.24MB +00:00:02 106MB | AOV samples 6.52MB +00:00:02 106MB | output buffers 0.20MB +00:00:02 106MB | framebuffers 0.31MB +00:00:02 106MB | node overhead 0.01MB +00:00:02 106MB | message passing 0.08MB +00:00:02 106MB | memory pools 30.05MB +00:00:02 106MB | geometry 0.00MB +00:00:02 106MB | accel. structs 0.01MB +00:00:02 106MB | strings 12.00MB +00:00:02 106MB | texture cache 3.00MB +00:00:02 106MB | profiler 0.01MB +00:00:02 106MB | unaccounted 11.33MB +00:00:02 106MB | ----------------------------------------------------------------------------------- +00:00:02 106MB | ray counts ( /pixel, /sample) (% total) (avg. hits) (max hits) +00:00:02 106MB | camera 192800 ( 10.04, 1.00) ( 54.88%) ( 0.09) ( 1) +00:00:02 106MB | shadow 22450 ( 1.17, 0.12) ( 6.39%) ( 0.29) ( 1) +00:00:02 106MB | diffuse_reflect 72556 ( 3.78, 0.38) ( 20.65%) ( 0.09) ( 1) +00:00:02 106MB | specular_reflect 63489 ( 3.31, 0.33) ( 18.07%) ( 0.08) ( 1) +00:00:02 106MB | total 351295 ( 18.30, 1.82) (100.00%) ( 0.10) ( 1) +00:00:02 106MB | by ray depth: 0 1 2 +00:00:02 106MB | total 59.7% 38.5% 1.8% +00:00:02 106MB | ----------------------------------------------------------------------------------- +00:00:02 106MB | shader calls ( /pixel, /sample) (% total) +00:00:02 106MB | primary 35781 ( 1.86, 0.19) (100.00%) +00:00:02 106MB | total 35781 ( 1.86, 0.19) (100.00%) +00:00:02 106MB | by ray depth: 0 1 2 +00:00:02 106MB | total 66.1% 24.3% 9.5% +00:00:02 106MB | ----------------------------------------------------------------------------------- +00:00:02 106MB | geometry (% hit ) (instances) ( init mem, final mem) +00:00:02 106MB | lists 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 106MB | procs 2 ( 50.0%) ( 0) ( 0.00, 0.00) +00:00:02 106MB | simple 2 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 106MB | ----------------------------------------------------------------------------------- +00:00:02 106MB | geometric elements ( min) ( avg.) ( max) +00:00:02 106MB | objects (procs) 2 ( 0) ( 1.0) ( 2) +00:00:02 106MB | ----------------------------------------------------------------------------------- +00:00:02 106MB | acceleration structures: (% total) +00:00:02 106MB | list 1 ( 50.00%) +00:00:02 106MB | bvh 1 ( 50.00%) +00:00:02 106MB | total 2 (100.00%) +00:00:02 106MB | ----------------------------------------------------------------------------------- +00:00:02 106MB | OpenImageIO Texture statistics +00:00:02 106MB | Options: gray_to_rgb=1 flip_t=0 max_tile_channels=6 +00:00:02 106MB | Queries/batches : +00:00:02 106MB | texture : 7117 queries in 7117 batches +00:00:02 106MB | texture 3d : 0 queries in 0 batches +00:00:02 106MB | shadow : 0 queries in 0 batches +00:00:02 106MB | environment : 0 queries in 0 batches +00:00:02 106MB | Interpolations : +00:00:02 106MB | closest : 0 +00:00:02 106MB | bilinear : 407 +00:00:02 106MB | bicubic : 6710 +00:00:02 106MB | Average anisotropic probes : 1 +00:00:02 106MB | Max anisotropy in the wild : 1 +00:00:02 106MB | +00:00:02 106MB | OpenImageIO ImageCache statistics (0000000003D00740) ver 2.1.0dev +00:00:02 106MB | Options: max_memory_MB=2048.0 max_open_files=1536 autotile=0 +00:00:02 106MB | autoscanline=1 automip=0 forcefloat=0 accept_untiled=1 +00:00:02 106MB | accept_unmipped=1 deduplicate=1 unassociatedalpha=0 +00:00:02 106MB | failure_retries=0 +00:00:02 106MB | Images : 1 unique +00:00:02 106MB | ImageInputs : 1 created, 0 current, 1 peak +00:00:02 106MB | Total pixel data size of all images referenced : 3.0 MB +00:00:02 106MB | Total actual file size of all images referenced : 10 KB +00:00:02 106MB | Pixel data read : 3.0 MB +00:00:02 106MB | File I/O time : 0.0s (0.0s average per thread, for 31 threads) +00:00:02 106MB | File open time only : 0.0s +00:00:02 106MB | Tiles: 1 created, 1 current, 1 peak +00:00:02 106MB | total tile requests : 55308 +00:00:02 106MB | micro-cache misses : 31 (0.0560498%) +00:00:02 106MB | main cache misses : 1 (0.00180806%) +00:00:02 106MB | redundant reads: 0 tiles, 0 B +00:00:02 106MB | Peak cache memory : 3.0 MB +00:00:02 106MB | Image file statistics: +00:00:02 106MB | opens tiles MB read --redundant-- I/O time res File +00:00:02 106MB | 1 1 1 3.0 0.0s 1024x1024x3.u8 d:/arnold/usd_procedural/build/windows_x86_64/msvc_opt/usd-0.18.11_arnold-5.3.0.0/testsuite/test_0013/mat_png.png UNTILED +00:00:02 106MB | +00:00:02 106MB | Tot: 1 1 3.0 ( 0 0.0) 0.0s +00:00:02 106MB | 1 not tiled, 1 not MIP-mapped +00:00:02 106MB | Broken or invalid files: 0 +00:00:02 106MB | ----------------------------------------------------------------------------------- +00:00:02 106MB | number of warnings, warning type: +00:00:02 106MB | 2: %s.%s: use type %s, not %s +00:00:02 106MB | 4: %s: could not set %s parameter "%s" +00:00:02 106MB | ----------------------------------------------------------------------------------- +00:00:02 106MB | performance warnings: +00:00:02 106MB WARNING | Rendering CPU utilization was only 1%. Your render may be bound by a single threaded process or I/O. +00:00:02 106MB | ----------------------------------------------------------------------------------- +00:00:02 103MB | +00:00:02 103MB | releasing resources +00:00:02 91MB | unloading 1 plugin +00:00:02 91MB | closing usd_proc.dll ... +00:00:02 82MB | unloading plugins done +00:00:02 82MB | Arnold shutdown diff --git a/testsuite/test_0013/ref/reference.tif b/testsuite/test_0013/ref/reference.tif new file mode 100755 index 0000000000..1a2f13383c Binary files /dev/null and b/testsuite/test_0013/ref/reference.tif differ diff --git a/testsuite/test_0014/README b/testsuite/test_0014/README new file mode 100755 index 0000000000..6d08007c6c --- /dev/null +++ b/testsuite/test_0014/README @@ -0,0 +1,6 @@ +Test Material bindings + +See trac#7814 + +author: sebastien ortega + diff --git a/testsuite/test_0014/data/scene.usda b/testsuite/test_0014/data/scene.usda new file mode 100755 index 0000000000..6ed6cbf673 --- /dev/null +++ b/testsuite/test_0014/data/scene.usda @@ -0,0 +1,26 @@ +#usda 1.0 + +def "World" +{ + def Cylinder "cylinder" + { + double radius=1.1 + double height=3 + token axis="Y" + float3 xformOp:translate= (0,0, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] + rel material:binding = + } + + def Material "material" + { + token outputs:surface.connect = + + def Shader "PreviewShader" + { + uniform token info:id = "UsdPreviewSurface" + color3f inputs:diffuseColor = (1,0,0) + } + } +} + diff --git a/testsuite/test_0014/data/test.ass b/testsuite/test_0014/data/test.ass new file mode 100755 index 0000000000..d82966e001 --- /dev/null +++ b/testsuite/test_0014/data/test.ass @@ -0,0 +1,111 @@ +### exported: Tue Dec 18 15:45:58 2018 +### from: Arnold 5.2.2.0 [30b8ba14] windows icc-17.0.2 oiio-2.0.1 osl-1.10.1 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 2018/12/04 22:02:04 +### host app: MtoA 3.1.3.wip 7d48f6c4 (develop) Maya 2018 +### bounds: -1 -1 -1 1 1 1 +### user: blaines +### render_layer: defaultRenderLayer +### scene: D:/arnold/scenes/usd_builtin.ma + + + +options +{ + AA_samples 3 + AA_samples_max 8 + outputs "RGBA RGBA myfilter mydriver" + xres 960 + yres 540 + texture_per_file_stats on + texture_automip off + camera "perspShape" + frame 1 + GI_diffuse_depth 1 + GI_specular_depth 1 + GI_transmission_depth 8 + declare render_layer constant STRING + render_layer "defaultRenderLayer" +} + +gaussian_filter +{ + name myfilter +} + +driver_tiff +{ + name mydriver + filename "testrender.tif" + color_space "sRGB" +} + +persp_camera +{ + name perspShape + matrix + 0.99999392 -1.08420217e-19 0.00349065149 0 + 0.000781565788 0.974611521 -0.223901182 0 + -0.00340202916 0.223902553 0.97460562 0 + -0.949623287 7.26941013 21.0998859 1 + near_clip 0.100000001 + far_clip 10000 + screen_window_min -1 -1 + screen_window_max 1 1 + shutter_start 0 + shutter_end 0 + shutter_type "box" + rolling_shutter "off" + rolling_shutter_duration 0 + motion_start 0 + motion_end 0 + exposure 0 + fov 34.4322243 + uv_remap 0 0 0 1 + declare maya_full_name constant STRING + maya_full_name "|persp|perspShape" +} + +distant_light +{ + name directionalLightShape1 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 0 0 1 + exposure 0 + cast_shadows on + cast_volumetric_shadows on + shadow_density 1 + samples 1 + normalize on + diffuse 1 + specular 1 + sss 1 + indirect 1 + max_bounces 999 + volume_samples 2 + volume 1 + aov "default" + angle 0 + declare maya_full_name constant STRING + maya_full_name "|directionalLight1|directionalLightShape1" +} + +usd +{ + name usd + visibility 255 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 0 0 1 + use_light_group off + override_nodes off + filename "scene.usda" + frame 1 + declare maya_full_name constant STRING + maya_full_name "|aiUsd1|aiUsdShape1" +} + + diff --git a/testsuite/test_0014/ref/reference.log b/testsuite/test_0014/ref/reference.log new file mode 100755 index 0000000000..206fa65580 --- /dev/null +++ b/testsuite/test_0014/ref/reference.log @@ -0,0 +1,176 @@ +00:00:00 52MB | log started Fri Apr 5 18:38:00 2019 +00:00:00 52MB | Arnold 5.3.0.0 [b452526e] windows icc-17.0.2 oiio-2.1.0 osl-1.11.0 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 optix-6.0.0 2019/03/20 01:03:22 +00:00:00 52MB | running on REM8WCK8D2, pid=12672 +00:00:00 52MB | 2 x Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz (20 cores, 40 logical) with 65458MB +00:00:00 52MB | NVIDIA driver version 391.03 +00:00:00 52MB | Windows 7 Enterprise Edition Service Pack 1 (version 6.1, build 7601) +00:00:00 52MB | soft limit for open files raised from 512 to 2048 +00:00:00 52MB | +00:00:00 52MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\plugins ... +00:00:00 52MB | usd_proc.dll: usd uses Arnold 5.3.0.0 +00:00:00 52MB | loaded 1 plugins from 1 lib(s) in 0:00.07 +00:00:00 52MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\bin\..\plugins ... +00:00:00 52MB | usd_proc.dll: usd uses Arnold 5.3.0.0 +00:00:00 52MB WARNING | node "usd" is already installed +00:00:00 52MB | loaded 1 plugins from 1 lib(s) in 0:00.00 +00:00:00 52MB | [kick] command: D:\arnold\releases\Arnold_latest-windows-usd\bin\kick test.ass -dw -r 160 120 -bs 16 -o testrender.tif -set driver_tiff.dither false -nocrashpopup -dp -v 6 -l D:\arnold\releases\Arnold_latest-windows-usd\plugins +00:00:00 52MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\plugins ... +00:00:00 52MB | no plugins loaded +00:00:00 52MB | loading plugins from . ... +00:00:00 52MB | no plugins loaded +00:00:00 52MB | [metadata] loading metadata file: test.ass +00:00:00 53MB | [ass] loading test.ass ... +00:00:00 53MB | [ass] read 2093 bytes, 6 nodes in 0:00.00 +00:00:00 53MB | [kick] applying 1 attr value override +00:00:00 53MB | +00:00:00 53MB | authorizing with default license managers: rlm, clm ... +00:00:02 63MB | [clm] authorized for "86985ARNOL_2018_0F" in 0:02.36 +00:00:02 63MB | [clm] expiration date: permanent, in use: 1/1000 +00:00:02 63MB | +00:00:02 63MB | [color_manager] no color manager is active +00:00:02 63MB | [color_manager] rendering color space is "linear" with declared chromaticities: +00:00:02 63MB | r(0.6400, 0.3300) g(0.3000, 0.6000) b(0.1500, 0.0600) and w(0.3127, 0.3290) +00:00:02 74MB | +00:00:02 74MB | there are 1 light and 2 objects: +00:00:02 74MB | 1 persp_camera +00:00:02 74MB | 1 distant_light +00:00:02 74MB | 1 utility +00:00:02 74MB | 1 driver_tiff +00:00:02 74MB | 1 gaussian_filter +00:00:02 74MB | 1 list_aggregate +00:00:02 74MB | 1 usd +00:00:02 74MB | +00:00:02 74MB | rendering image at 160 x 120, 3 AA samples +00:00:02 74MB | AA samples max +00:00:02 74MB | AA sample clamp +00:00:02 74MB | diffuse samples 2 / depth 1 +00:00:02 74MB | specular samples 2 / depth 1 +00:00:02 74MB | transmission samples 2 / depth 8 +00:00:02 74MB | volume indirect +00:00:02 74MB | total depth 10 +00:00:02 74MB | bssrdf samples 2 +00:00:02 74MB | transparency depth 10 +00:00:02 74MB | initializing 8 nodes ... +00:00:02 86MB WARNING | /World/material/PreviewShader: could not set FLOAT parameter " specular_IOR " +00:00:02 86MB WARNING | /World/material/PreviewShader.opacity: use type RGB, not FLOAT +00:00:02 86MB WARNING | /World/material/PreviewShader: could not set FLOAT parameter "opacity" +00:00:02 86MB | [proc] usd: loaded 2 nodes (1 objects, 1 shaders) +00:00:02 86MB | creating root object list ... +00:00:02 86MB | node initialization done in 0:00.09 (multithreaded) +00:00:02 86MB | updating 11 nodes ... +00:00:02 86MB | directionalLightShape1: distant_light using 1 sample, 2 volume samples +00:00:02 86MB | scene bounds: (-1.10000098 -1.5 -1.10000098) -> (1.10000098 1.5 1.10000098) +00:00:02 86MB | node update done in 0:00.00 (multithreaded) +00:00:02 86MB | [aov] parsing 1 output statements ... +00:00:02 86MB | [aov] registered driver: "mydriver" (driver_tiff) +00:00:02 86MB | [aov] * "RGBA" of type RGBA filtered by "myfilter" (gaussian_filter) +00:00:02 87MB | [aov] done preparing 2 AOVs for 1 output to 1 driver (0 deep AOVs) +00:00:02 87MB | starting 40 bucket workers of size 16x16 ... +00:00:02 92MB | 0% done - 5 rays/pixel +00:00:02 92MB | 5% done - 19 rays/pixel +00:00:02 92MB | 10% done - 16 rays/pixel +00:00:02 93MB | 15% done - 10 rays/pixel +00:00:02 93MB | 20% done - 12 rays/pixel +00:00:02 93MB | 25% done - 16 rays/pixel +00:00:02 93MB | 30% done - 13 rays/pixel +00:00:02 93MB | 35% done - 14 rays/pixel +00:00:02 93MB | 40% done - 18 rays/pixel +00:00:02 93MB | 45% done - 4 rays/pixel +00:00:02 93MB | 50% done - 18 rays/pixel +00:00:02 94MB | 55% done - 0 rays/pixel +00:00:02 94MB | 60% done - 0 rays/pixel +00:00:02 94MB | 65% done - 0 rays/pixel +00:00:02 94MB | 70% done - 0 rays/pixel +00:00:02 94MB | 75% done - 0 rays/pixel +00:00:02 94MB | 80% done - 0 rays/pixel +00:00:02 94MB | 85% done - 0 rays/pixel +00:00:02 94MB | 90% done - 0 rays/pixel +00:00:02 94MB | 95% done - 0 rays/pixel +00:00:02 94MB | 100% done - 0 rays/pixel +00:00:02 94MB | render done in 0:00.020 +00:00:02 94MB | [driver_tiff] writing file `testrender.tif' +00:00:02 95MB | render done +00:00:02 95MB | +00:00:02 95MB | ----------------------------------------------------------------------------------- +00:00:02 95MB | scene creation time 0:00.11 machine utilization (0.35%) +00:00:02 95MB | plugin loading 0:00.08 +00:00:02 95MB | unaccounted 0:00.02 +00:00:02 95MB | ----------------------------------------------------------------------------------- +00:00:02 95MB | frame time 0:02.51 machine utilization (2.68%) +00:00:02 95MB | node init 0:00.09 +00:00:02 95MB | rendering 0:00.02 +00:00:02 95MB | pixel rendering 0:00.02 +00:00:02 95MB | unaccounted 0:02.38 +00:00:02 95MB | ----------------------------------------------------------------------------------- +00:00:02 95MB | top session self-times by category +00:00:02 95MB | worker waiting 0:02.48 (95.89%) +00:00:02 95MB | InitializeNodes 0:00.08 ( 3.35%) +00:00:02 95MB | TraceCameraRay 0:00.00 ( 0.15%) +00:00:02 95MB | thread blocked 0:00.00 ( 0.13%) +00:00:02 95MB | node_init 0:00.00 ( 0.09%) +00:00:02 95MB | initializeAllNodes 0:00.00 ( 0.09%) +00:00:02 95MB | ----------------------------------------------------------------------------------- +00:00:02 95MB | top session self-times by node +00:00:02 95MB | worker waiting 0:02.48 (95.89%) +00:00:02 95MB | InitializeNodes 0:00.08 ( 3.35%) +00:00:02 95MB | TraceCameraRay 0:00.00 ( 0.15%) +00:00:02 95MB | thread blocked 0:00.00 ( 0.13%) +00:00:02 95MB | standard_surface:/World/material/PreviewShader 0:00.00 ( 0.11%) +00:00:02 95MB | initializeAllNodes 0:00.00 ( 0.09%) +00:00:02 95MB | ----------------------------------------------------------------------------------- +00:00:02 95MB | peak CPU memory used 95.07MB +00:00:02 95MB | at startup 36.86MB +00:00:02 95MB | plugins 6.64MB +00:00:02 95MB | AOV samples 6.52MB +00:00:02 95MB | output buffers 0.23MB +00:00:02 95MB | framebuffers 0.31MB +00:00:02 95MB | node overhead 0.00MB +00:00:02 95MB | message passing 0.08MB +00:00:02 95MB | memory pools 30.05MB +00:00:02 95MB | geometry 0.00MB +00:00:02 95MB | strings 12.00MB +00:00:02 95MB | profiler 0.01MB +00:00:02 95MB | unaccounted 2.36MB +00:00:02 95MB | ----------------------------------------------------------------------------------- +00:00:02 95MB | ray counts ( /pixel, /sample) (% total) (avg. hits) (max hits) +00:00:02 95MB | camera 192800 ( 10.04, 1.00) ( 66.28%) ( 0.05) ( 1) +00:00:02 95MB | shadow 14716 ( 0.77, 0.08) ( 5.06%) ( 0.40) ( 1) +00:00:02 95MB | diffuse_reflect 45005 ( 2.34, 0.23) ( 15.47%) ( 0.13) ( 1) +00:00:02 95MB | specular_reflect 38378 ( 2.00, 0.20) ( 13.19%) ( 0.11) ( 1) +00:00:02 95MB | total 290899 ( 15.15, 1.51) (100.00%) ( 0.09) ( 1) +00:00:02 95MB | by ray depth: 0 1 2 +00:00:02 95MB | total 69.8% 28.3% 1.9% +00:00:02 95MB | ----------------------------------------------------------------------------------- +00:00:02 95MB | shader calls ( /pixel, /sample) (% total) +00:00:02 95MB | primary 20164 ( 1.05, 0.10) (100.00%) +00:00:02 95MB | total 20164 ( 1.05, 0.10) (100.00%) +00:00:02 95MB | by ray depth: 0 1 2 +00:00:02 95MB | total 50.8% 35.7% 13.5% +00:00:02 95MB | ----------------------------------------------------------------------------------- +00:00:02 95MB | geometry (% hit ) (instances) ( init mem, final mem) +00:00:02 95MB | lists 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 95MB | procs 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 95MB | simple 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 95MB | ----------------------------------------------------------------------------------- +00:00:02 95MB | geometric elements ( min) ( avg.) ( max) +00:00:02 95MB | objects (procs) 1 ( 1) ( 1.0) ( 1) +00:00:02 95MB | ----------------------------------------------------------------------------------- +00:00:02 95MB | acceleration structures: (% total) +00:00:02 95MB | list 2 (100.00%) +00:00:02 95MB | total 2 (100.00%) +00:00:02 95MB | ----------------------------------------------------------------------------------- +00:00:02 95MB | number of warnings, warning type: +00:00:02 95MB | 1: %s.%s: use type %s, not %s +00:00:02 95MB | 2: %s: could not set %s parameter "%s" +00:00:02 95MB | 1: node "%s" is already installed +00:00:02 95MB | ----------------------------------------------------------------------------------- +00:00:02 95MB | performance warnings: +00:00:02 95MB WARNING | Rendering CPU utilization was only 3%. Your render may be bound by a single threaded process or I/O. +00:00:02 95MB | ----------------------------------------------------------------------------------- +00:00:02 91MB | +00:00:02 91MB | releasing resources +00:00:02 78MB | unloading 2 plugins +00:00:02 78MB | closing usd_proc.dll ... +00:00:02 78MB | closing usd_proc.dll ... +00:00:02 69MB | unloading plugins done +00:00:02 69MB | Arnold shutdown diff --git a/testsuite/test_0014/ref/reference.tif b/testsuite/test_0014/ref/reference.tif new file mode 100755 index 0000000000..91de7ca783 Binary files /dev/null and b/testsuite/test_0014/ref/reference.tif differ diff --git a/testsuite/test_0015/README b/testsuite/test_0015/README new file mode 100755 index 0000000000..760fc15ed9 --- /dev/null +++ b/testsuite/test_0015/README @@ -0,0 +1,4 @@ +Test Arnold typed shaders and nodes + +author: sebastien ortega + diff --git a/testsuite/test_0015/data/scene.usda b/testsuite/test_0015/data/scene.usda new file mode 100755 index 0000000000..11f82ca004 --- /dev/null +++ b/testsuite/test_0015/data/scene.usda @@ -0,0 +1,72 @@ +#usda 1.0 + +def "World" +{ + def Cylinder "cylinder" + { + double radius=1.1 + double height=3 + token axis="Y" + float3 xformOp:translate= (0,0, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] + rel material:binding = + } + + def Material "material" + { + token outputs:surface.connect = + + def Shader "PreviewShader" + { + uniform token info:id = "arnold:flat" + color3f inputs:color = (0,0,1) + } + } + + def Cone "cone" + { + double radius=1.1 + double height=3 + token axis="Y" + float3 xformOp:translate= (5,0, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] + rel material:binding = + } + + def Material "material2" + { + token outputs:surface.connect = + + def Shader "PreviewShader" + { + uniform token info:id = "arnold:standard_surface" + color3f inputs:base_color = (0.5,1,1) + } + } + + def Cube "cube" + { + float3 xformOp:translate= (-5,0, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] + rel material:binding = + } + + def Material "material3" + { + token outputs:surface.connect = + + def Shader "PreviewShader" + { + uniform token info:id = "arnold:utility" + color3f inputs:color = (1, 0, 0) + } + } + + def ArnoldSkydomeLight "light" + { + float arnold:intensity = 1 + color3f arnold:color = (1, 0.4, 1) + float arnold:camera = 0.5 + } +} + diff --git a/testsuite/test_0015/data/test.ass b/testsuite/test_0015/data/test.ass new file mode 100755 index 0000000000..ee58c4d5ab --- /dev/null +++ b/testsuite/test_0015/data/test.ass @@ -0,0 +1,85 @@ +### exported: Tue Dec 18 15:45:58 2018 +### from: Arnold 5.2.2.0 [30b8ba14] windows icc-17.0.2 oiio-2.0.1 osl-1.10.1 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 2018/12/04 22:02:04 +### host app: MtoA 3.1.3.wip 7d48f6c4 (develop) Maya 2018 +### bounds: -1 -1 -1 1 1 1 +### user: blaines +### render_layer: defaultRenderLayer +### scene: D:/arnold/scenes/usd_builtin.ma + + + +options +{ + AA_samples 3 + AA_samples_max 8 + outputs "RGBA RGBA myfilter mydriver" + xres 960 + yres 540 + texture_per_file_stats on + texture_automip off + camera "perspShape" + frame 1 + GI_diffuse_depth 1 + GI_specular_depth 1 + GI_transmission_depth 8 + declare render_layer constant STRING + render_layer "defaultRenderLayer" +} + +gaussian_filter +{ + name myfilter +} + +driver_tiff +{ + name mydriver + filename "testrender.tif" + color_space "sRGB" +} + +persp_camera +{ + name perspShape + matrix + 0.99999392 -1.08420217e-19 0.00349065149 0 + 0.000781565788 0.974611521 -0.223901182 0 + -0.00340202916 0.223902553 0.97460562 0 + -0.949623287 7.26941013 21.0998859 1 + near_clip 0.100000001 + far_clip 10000 + screen_window_min -1 -1 + screen_window_max 1 1 + shutter_start 0 + shutter_end 0 + shutter_type "box" + rolling_shutter "off" + rolling_shutter_duration 0 + motion_start 0 + motion_end 0 + exposure 0 + fov 34.4322243 + uv_remap 0 0 0 1 + declare maya_full_name constant STRING + maya_full_name "|persp|perspShape" +} + + +usd +{ + name usd + visibility 255 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 0 0 1 + use_light_group off + override_nodes off + filename "scene.usda" + frame 1 + declare maya_full_name constant STRING + maya_full_name "|aiUsd1|aiUsdShape1" +} + + diff --git a/testsuite/test_0015/ref/reference.log b/testsuite/test_0015/ref/reference.log new file mode 100755 index 0000000000..06c393f013 --- /dev/null +++ b/testsuite/test_0015/ref/reference.log @@ -0,0 +1,173 @@ +00:00:00 52MB | log started Fri Apr 5 18:39:41 2019 +00:00:00 52MB | Arnold 5.3.0.0 [b452526e] windows icc-17.0.2 oiio-2.1.0 osl-1.11.0 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 optix-6.0.0 2019/03/20 01:03:22 +00:00:00 52MB | running on REM8WCK8D2, pid=6344 +00:00:00 52MB | 2 x Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz (20 cores, 40 logical) with 65458MB +00:00:00 52MB | NVIDIA driver version 391.03 +00:00:00 52MB | Windows 7 Enterprise Edition Service Pack 1 (version 6.1, build 7601) +00:00:00 52MB | soft limit for open files raised from 512 to 2048 +00:00:00 52MB | +00:00:00 52MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\plugins ... +00:00:00 52MB | usd_proc.dll: usd uses Arnold 5.3.0.0 +00:00:00 52MB | loaded 1 plugins from 1 lib(s) in 0:00.07 +00:00:00 52MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\bin\..\plugins ... +00:00:00 52MB | usd_proc.dll: usd uses Arnold 5.3.0.0 +00:00:00 52MB WARNING | node "usd" is already installed +00:00:00 52MB | loaded 1 plugins from 1 lib(s) in 0:00.00 +00:00:00 52MB | [kick] command: D:\arnold\releases\Arnold_latest-windows-usd\bin\kick test.ass -dw -r 160 120 -bs 16 -o testrender.tif -set driver_tiff.dither false -nocrashpopup -dp -v 6 -l D:\arnold\releases\Arnold_latest-windows-usd\plugins +00:00:00 52MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\plugins ... +00:00:00 52MB | no plugins loaded +00:00:00 52MB | loading plugins from . ... +00:00:00 52MB | no plugins loaded +00:00:00 52MB | [metadata] loading metadata file: test.ass +00:00:00 53MB | [ass] loading test.ass ... +00:00:00 53MB | [ass] read 1665 bytes, 5 nodes in 0:00.00 +00:00:00 53MB | [kick] applying 1 attr value override +00:00:00 53MB | +00:00:00 53MB | authorizing with default license managers: rlm, clm ... +00:00:02 63MB | [clm] authorized for "86985ARNOL_2018_0F" in 0:02.35 +00:00:02 63MB | [clm] expiration date: permanent, in use: 1/1000 +00:00:02 63MB | +00:00:02 63MB | [color_manager] no color manager is active +00:00:02 63MB | [color_manager] rendering color space is "linear" with declared chromaticities: +00:00:02 63MB | r(0.6400, 0.3300) g(0.3000, 0.6000) b(0.1500, 0.0600) and w(0.3127, 0.3290) +00:00:02 74MB | +00:00:02 74MB | there are 0 lights and 2 objects: +00:00:02 74MB | 1 persp_camera +00:00:02 74MB | 1 utility +00:00:02 74MB | 1 driver_tiff +00:00:02 74MB | 1 gaussian_filter +00:00:02 74MB | 1 list_aggregate +00:00:02 74MB | 1 usd +00:00:02 74MB | +00:00:02 74MB | rendering image at 160 x 120, 3 AA samples +00:00:02 74MB | AA samples max +00:00:02 74MB | AA sample clamp +00:00:02 74MB | diffuse samples 2 / depth 1 +00:00:02 74MB | specular samples 2 / depth 1 +00:00:02 74MB | transmission samples 2 / depth 8 +00:00:02 74MB | volume indirect +00:00:02 74MB | total depth 10 +00:00:02 74MB | bssrdf samples 2 +00:00:02 74MB | transparency depth 10 +00:00:02 74MB | initializing 7 nodes ... +00:00:02 87MB | [proc] usd: loaded 7 nodes (3 objects, 3 shaders) +00:00:02 87MB | creating root object list ... +00:00:02 87MB | node initialization done in 0:00.06 (multithreaded) +00:00:02 87MB | updating 15 nodes ... +00:00:02 87MB | /World/light: skydome_light using 1 sample, 2 volume samples +00:00:02 87MB | scene bounds: (-6 -2.5999999 -1.10000098) -> (6.0999999 1.5 1.10000098) +00:00:02 87MB | node update done in 0:00.00 (multithreaded) +00:00:02 87MB | [aov] parsing 1 output statements ... +00:00:02 87MB | [aov] registered driver: "mydriver" (driver_tiff) +00:00:02 87MB | [aov] * "RGBA" of type RGBA filtered by "myfilter" (gaussian_filter) +00:00:02 87MB | [aov] done preparing 2 AOVs for 1 output to 1 driver (0 deep AOVs) +00:00:02 88MB | starting 40 bucket workers of size 16x16 ... +00:00:02 93MB | [accel] procedural bvh4 done - 0:00.00 (wall time) - 3 prims, 1 key +00:00:02 94MB | 0% done - 7 rays/pixel +00:00:02 94MB | 5% done - 10 rays/pixel +00:00:02 94MB | 10% done - 24 rays/pixel +00:00:02 94MB | 15% done - 5 rays/pixel +00:00:02 94MB | 20% done - 5 rays/pixel +00:00:02 94MB | 25% done - 3 rays/pixel +00:00:02 95MB | 30% done - 9 rays/pixel +00:00:02 95MB | 35% done - 21 rays/pixel +00:00:02 95MB | 40% done - 10 rays/pixel +00:00:02 95MB | 45% done - 9 rays/pixel +00:00:02 95MB | 50% done - 11 rays/pixel +00:00:02 95MB | 55% done - 38 rays/pixel +00:00:02 95MB | 60% done - 64 rays/pixel +00:00:02 95MB | 65% done - 66 rays/pixel +00:00:02 95MB | 70% done - 56 rays/pixel +00:00:02 95MB | 75% done - 163 rays/pixel +00:00:02 95MB | 80% done - 0 rays/pixel +00:00:02 96MB | 85% done - 0 rays/pixel +00:00:02 96MB | 90% done - 0 rays/pixel +00:00:02 96MB | 95% done - 0 rays/pixel +00:00:02 96MB | 100% done - 0 rays/pixel +00:00:02 96MB | render done in 0:00.017 +00:00:02 96MB | [driver_tiff] writing file `testrender.tif' +00:00:02 96MB | render done +00:00:02 96MB | +00:00:02 96MB | ----------------------------------------------------------------------------------- +00:00:02 96MB | scene creation time 0:00.11 machine utilization (0.00%) +00:00:02 96MB | plugin loading 0:00.08 +00:00:02 96MB | unaccounted 0:00.02 +00:00:02 96MB | ----------------------------------------------------------------------------------- +00:00:02 96MB | frame time 0:02.47 machine utilization (1.94%) +00:00:02 96MB | node init 0:00.06 +00:00:02 96MB | rendering 0:00.01 +00:00:02 96MB | pixel rendering 0:00.01 +00:00:02 96MB | unaccounted 0:02.38 +00:00:02 96MB | ----------------------------------------------------------------------------------- +00:00:02 96MB | top session self-times by category +00:00:02 96MB | worker waiting 0:02.47 (97.01%) +00:00:02 96MB | InitializeNodes 0:00.05 ( 2.28%) +00:00:02 96MB | thread blocked 0:00.00 ( 0.18%) +00:00:02 96MB | TraceCameraRay 0:00.00 ( 0.11%) +00:00:02 96MB | Plugin loader 0:00.00 ( 0.08%) +00:00:02 96MB | node_init (usd) 0:00.00 ( 0.07%) +00:00:02 96MB | ----------------------------------------------------------------------------------- +00:00:02 96MB | top session self-times by node +00:00:02 96MB | worker waiting 0:02.47 (97.01%) +00:00:02 96MB | InitializeNodes 0:00.05 ( 2.28%) +00:00:02 96MB | thread blocked 0:00.00 ( 0.14%) +00:00:02 96MB | usd 0:00.00 ( 0.13%) +00:00:02 96MB | TraceCameraRay 0:00.00 ( 0.11%) +00:00:02 96MB | Plugin loader 0:00.00 ( 0.08%) +00:00:02 96MB | ----------------------------------------------------------------------------------- +00:00:02 96MB | peak CPU memory used 96.32MB +00:00:02 96MB | at startup 36.83MB +00:00:02 96MB | plugins 6.55MB +00:00:02 96MB | AOV samples 6.52MB +00:00:02 96MB | output buffers 0.23MB +00:00:02 96MB | framebuffers 0.31MB +00:00:02 96MB | node overhead 0.01MB +00:00:02 96MB | message passing 0.08MB +00:00:02 96MB | memory pools 30.05MB +00:00:02 96MB | geometry 0.00MB +00:00:02 96MB | accel. structs 0.01MB +00:00:02 96MB | strings 12.00MB +00:00:02 96MB | profiler 0.01MB +00:00:02 96MB | unaccounted 3.72MB +00:00:02 96MB | ----------------------------------------------------------------------------------- +00:00:02 96MB | ray counts ( /pixel, /sample) (% total) (avg. hits) (max hits) +00:00:02 96MB | camera 192800 ( 10.04, 1.00) ( 69.58%) ( 0.12) ( 1) +00:00:02 96MB | shadow 42154 ( 2.20, 0.22) ( 15.21%) ( 0.06) ( 1) +00:00:02 96MB | diffuse_reflect 21100 ( 1.10, 0.11) ( 7.61%) ( 0.04) ( 1) +00:00:02 96MB | specular_reflect 21054 ( 1.10, 0.11) ( 7.60%) ( 0.08) ( 1) +00:00:02 96MB | total 277108 ( 14.43, 1.44) (100.00%) ( 0.10) ( 1) +00:00:02 96MB | by ray depth: 0 1 +00:00:02 96MB | total 84.8% 15.2% +00:00:02 96MB | ----------------------------------------------------------------------------------- +00:00:02 96MB | shader calls ( /pixel, /sample) (% total) +00:00:02 96MB | primary 25833 ( 1.35, 0.13) (100.00%) +00:00:02 96MB | total 25833 ( 1.35, 0.13) (100.00%) +00:00:02 96MB | by ray depth: 0 1 +00:00:02 96MB | total 90.4% 9.6% +00:00:02 96MB | ----------------------------------------------------------------------------------- +00:00:02 96MB | geometry (% hit ) (instances) ( init mem, final mem) +00:00:02 96MB | lists 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 96MB | procs 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 96MB | simple 3 (100.0%) ( 0) ( 0.00, 0.00) +00:00:02 96MB | ----------------------------------------------------------------------------------- +00:00:02 96MB | geometric elements ( min) ( avg.) ( max) +00:00:02 96MB | objects (procs) 3 ( 3) ( 3.0) ( 3) +00:00:02 96MB | ----------------------------------------------------------------------------------- +00:00:02 96MB | acceleration structures: (% total) +00:00:02 96MB | list 1 ( 50.00%) +00:00:02 96MB | bvh 1 ( 50.00%) +00:00:02 96MB | total 2 (100.00%) +00:00:02 96MB | ----------------------------------------------------------------------------------- +00:00:02 96MB | number of warnings, warning type: +00:00:02 96MB | 1: node "%s" is already installed +00:00:02 96MB | ----------------------------------------------------------------------------------- +00:00:02 96MB | performance warnings: +00:00:02 96MB WARNING | Rendering CPU utilization was only 2%. Your render may be bound by a single threaded process or I/O. +00:00:02 96MB | ----------------------------------------------------------------------------------- +00:00:02 92MB | +00:00:02 92MB | releasing resources +00:00:02 79MB | unloading 2 plugins +00:00:02 79MB | closing usd_proc.dll ... +00:00:02 79MB | closing usd_proc.dll ... +00:00:02 70MB | unloading plugins done +00:00:02 70MB | Arnold shutdown diff --git a/testsuite/test_0015/ref/reference.tif b/testsuite/test_0015/ref/reference.tif new file mode 100755 index 0000000000..fb82f6006a Binary files /dev/null and b/testsuite/test_0015/ref/reference.tif differ diff --git a/testsuite/test_0016/README b/testsuite/test_0016/README new file mode 100755 index 0000000000..87465c9915 --- /dev/null +++ b/testsuite/test_0016/README @@ -0,0 +1,4 @@ +Kitchen scene + +author: sebastien ortega + diff --git a/testsuite/test_0016/data/Kitchen_set.usd b/testsuite/test_0016/data/Kitchen_set.usd new file mode 100755 index 0000000000..302fcd1b84 --- /dev/null +++ b/testsuite/test_0016/data/Kitchen_set.usd @@ -0,0 +1,5321 @@ +#usda 1.0 +( + defaultPrim = "Kitchen_set" + upAxis = "Z" +) + +def Xform "Kitchen_set" ( + kind = "assembly" +) +{ + def Xform "Arch_grp" ( + kind = "group" + ) + { + def "Kitchen_1" ( + add references = @./assets/Kitchen/Kitchen.usd@ + ) + { + double3 xformOp:translate = (71.10783386230469, -43.28064727783203, -1.8192274570465088) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + } + + def Xform "Props_grp" ( + kind = "group" + ) + { + def Xform "North_grp" ( + kind = "group" + ) + { + def Xform "NorthWall_grp" ( + kind = "group" + ) + { + def "MeasuringSpoon_1" ( + add references = @./assets/MeasuringSpoon/MeasuringSpoon.usd@ + ) + { + float3 xformOp:rotateXYZ = (180, 3.0688782, 180) + double3 xformOp:translate = (64.05464171919128, 116.96782967155194, 164.17722329084413) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "MeasuringSpoon_2" ( + add references = @./assets/MeasuringSpoon/MeasuringSpoon.usd@ + ) + { + float3 xformOp:rotateXYZ = (177.16803, -22.15876, -178.81621) + float3 xformOp:scale = (0.9414519, 0.9414519, 0.94145185) + double3 xformOp:translate = (64.55051974686009, 116.71268259148077, 164.13506315350196) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "MeasuringSpoon_3" ( + add references = @./assets/MeasuringSpoon/MeasuringSpoon.usd@ + ) + { + float3 xformOp:rotateXYZ = (-169.41438, 0.14698854, -178.15677) + float3 xformOp:scale = (0.790968, 0.790968, 0.790968) + double3 xformOp:translate = (63.984297073192344, 116.6034061485226, 163.9134405033258) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "MeasuringSpoon_4" ( + add references = @./assets/MeasuringSpoon/MeasuringSpoon.usd@ + ) + { + float3 xformOp:rotateXYZ = (-158.73116, -1.1479981, -177.79655) + float3 xformOp:scale = (0.63180304, 0.631803, 0.6318031) + double3 xformOp:translate = (64.22677508191487, 116.40149868037163, 163.89740948062274) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "NailA_1" ( + add references = @./assets/Nail/Nail.usd@ + variants = { + string modelingVariant = "NailA" + } + ) + { + float xformOp:rotateX = 90.17437 + double3 xformOp:translate = (110.44506072998048, 139.68678325465075, 173.63607617312698) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateX"] + } + + def "NailB_1" ( + add references = @./assets/Nail/Nail.usd@ + variants = { + string modelingVariant = "NailB" + } + ) + { + float xformOp:rotateX = 84.727715 + double3 xformOp:translate = (131.40843200683594, 140.21150969755237, 226.0142803643494) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateX"] + } + + def "PanB_1" ( + add references = @./assets/Pan/Pan.usd@ + variants = { + string modelingVariant = "PanB" + } + ) + { + float xformOp:rotateX = 89.835365 + double3 xformOp:translate = (131.21405029296872, 137.48016192242181, 190.93882477441954) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateX"] + } + + def "PotBLight_1" ( + add references = @./assets/Pot/Pot.usd@ + variants = { + string modelingVariant = "PotB" + string shadingVariant = "Light" + } + ) + { + float3 xformOp:rotateXYZ = (0.21586081, -0.025017224, -83.38828) + float3 xformOp:scale = (0.84849447, 0.84849447, 0.8484944) + double3 xformOp:translate = (67.36286491444208, 119.32041618820014, 176.29725567328825) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "PotBLight_2" ( + add references = @./assets/Pot/Pot.usd@ + variants = { + string modelingVariant = "PotB" + string shadingVariant = "Light" + } + ) + { + float3 xformOp:rotateXYZ = (-1.6485463, -0.7080394, -113.237) + float3 xformOp:scale = (0.8038945, 0.8038945, 0.8038945) + double3 xformOp:translate = (67.30359208525739, 119.3840494515122, 177.70700427475697) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "PotBDark_1" ( + add references = @./assets/Pot/Pot.usd@ + variants = { + string modelingVariant = "PotB" + string shadingVariant = "Dark" + } + ) + { + float xformOp:rotateZ = -39.80775 + double3 xformOp:translate = (67.32640154469226, 119.4149340930478, 174.11773681640625) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZ"] + } + + def "PotBDark_2" ( + add references = @./assets/Pot/Pot.usd@ + variants = { + string modelingVariant = "PotB" + string shadingVariant = "Dark" + } + ) + { + float3 xformOp:rotateXYZ = (2.7264502, -0.108684376, -87.71904) + float3 xformOp:scale = (0.6980213, 0.69802123, 0.69802123) + double3 xformOp:translate = (67.39044637660916, 119.32208432481471, 179.34163340213956) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "Strainer_1" ( + add references = @./assets/Strainer/Strainer.usd@ + ) + { + float xformOp:rotateX = -90.03959 + double3 xformOp:translate = (95.02201080322264, 127.89279432640326, 201.02645425859802) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateX"] + } + + def "BottleLargeRose_1" ( + add references = @./assets/BottleB/BottleB.usd@ + variants = { + string modelingVariant = "Large" + string shadingVariant = "Rose" + } + ) + { + float xformOp:rotateX = 0.0000014169925 + float3 xformOp:scale = (1.0899487, 1.0899487, 1.0899487) + double3 xformOp:translate = (29.369222811569472, 133.12659887216014, 174.20452668205746) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateX", "xformOp:scale"] + } + + def "JarA_1" ( + add references = @./assets/Jar/Jar.usd@ + variants = { + string modelingVariant = "JarA" + } + ) + { + double3 xformOp:translate = (54.025108337402344, 130.71880340576172, 174.10775756835938) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "JarB_1" ( + add references = @./assets/Jar/Jar.usd@ + variants = { + string modelingVariant = "JarB" + } + ) + { + double3 xformOp:translate = (40.130200035355614, 122.91436172577338, 174.0631561279297) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "OilBottle_1" ( + add references = @./assets/OilBottle/OilBottle.usd@ + ) + { + double3 xformOp:translate = (20.28419589996338, 117.52690887451172, 174.06820678710938) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "OilBottle_2" ( + add references = @./assets/OilBottle/OilBottle.usd@ + ) + { + float3 xformOp:rotateXYZ = (0.33192313, 0.7775182, 24.522833) + float3 xformOp:scale = (0.5498083, 0.54980826, 0.54980826) + double3 xformOp:translate = (47.65926140192843, 116.64242309134892, 174.3508599255582) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "SaltShaker_1" ( + add references = @./assets/SaltShaker/SaltShaker.usd@ + ) + { + double3 xformOp:translate = (31.01395320892334, 124.6248893737793, 174.12039184570312) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "SaltShakerShakerPepper_1" ( + add references = @./assets/SaltShaker/SaltShaker.usd@ + variants = { + string shadingVariant = "ShakerPepper" + } + ) + { + double3 xformOp:translate = (26.786664962768555, 119.41778945922852, 174.09774780273438) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "SpiceBox_1" ( + add references = @./assets/SpiceBox/SpiceBox.usd@ + ) + { + double3 xformOp:translate = (32.65584087371826, 119.22630310058594, 174.1240692138672) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "SpiceBox_2" ( + add references = @./assets/SpiceBox/SpiceBox.usd@ + ) + { + float3 xformOp:rotateXYZ = (-0.0000103521925, 0.0000058013907, -60.13755) + float3 xformOp:scale = (3.5935133, 3.5935133, 3.5935133) + double3 xformOp:translate = (24.00406902515698, 122.01378330221111, 174.65626961685018) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "SpiceShaker_1" ( + add references = @./assets/SpiceShaker/SpiceShaker.usd@ + ) + { + double3 xformOp:translate = (52.326555252075195, 117.52692794799805, 174.11839294433594) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "SpiceShaker_2" ( + add references = @./assets/SpiceShaker/SpiceShaker.usd@ + ) + { + float xformOp:rotateY = 0.000004335765 + float3 xformOp:scale = (0.7081966, 0.7081966, 0.7081965) + double3 xformOp:translate = (57.545063300127445, 119.18156196440424, 174.11336768960618) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateY", "xformOp:scale"] + } + + def "BottleShort_1" ( + add references = @./assets/Bottle/Bottle.usd@ + variants = { + string modelingVariant = "Short" + } + ) + { + double3 xformOp:translate = (67.9914436340332, 132.99644470214844, 174.0780517578125) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "CastIron_1" ( + add references = @./assets/CastIron/CastIron.usd@ + ) + { + float xformOp:rotateX = 90.90367 + double3 xformOp:translate = (110.9352912902832, 137.45110722903823, 150.74248350294582) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateX"] + } + + def "CupB_1" ( + add references = @./assets/Cup/Cup.usd@ + variants = { + string modelingVariant = "CupB" + } + ) + { + float3 xformOp:rotateXYZ = (42.61442, -0.15205921, -89.834724) + double3 xformOp:translate = (19.67116745027677, 115.85004461269241, 152.22999021307018) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "CupCBlue_1" ( + add references = @./assets/Cup/Cup.usd@ + variants = { + string modelingVariant = "CupC" + string shadingVariant = "Blue" + } + ) + { + float3 xformOp:rotateXYZ = (45.326336, 0.6660371, -90.65843) + float3 xformOp:scale = (0.8695379, 0.86953783, 0.86953783) + double3 xformOp:translate = (35.03757436041194, 115.21178844673375, 151.8788086680983) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "Hook_1" ( + add references = @./assets/Hook/Hook.usd@ + ) + { + float3 xformOp:rotateXYZ = (-4.308511e-7, 0.0000011879832, 89.85618) + float3 xformOp:scale = (0.9999994, 0.9999994, 0.9999994) + double3 xformOp:translate = (56.52762648741177, 116.32290199103622, 162.97122984837702) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "Hook_2" ( + add references = @./assets/Hook/Hook.usd@ + ) + { + float3 xformOp:rotateXYZ = (-2.5560448e-7, 0.0000011884232, 89.85618) + float3 xformOp:scale = (0.99999934, 0.99999934, 0.99999934) + double3 xformOp:translate = (64.08093012688583, 116.32289537885256, 162.97121997072875) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "Hook_3" ( + add references = @./assets/Hook/Hook.usd@ + ) + { + float3 xformOp:rotateXYZ = (-5.4664927e-8, 7.528387e-7, 94.982315) + float3 xformOp:scale = (0.99999946, 0.99999946, 0.9999995) + double3 xformOp:translate = (49.312609987174234, 116.32295539540188, 162.97121923059512) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "Hook_4" ( + add references = @./assets/Hook/Hook.usd@ + ) + { + float xformOp:rotateZ = 94.97184 + double3 xformOp:translate = (43.11128997802734, 116.3229446411133, 162.97122192382812) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZ"] + } + + def "Hook_5" ( + add references = @./assets/Hook/Hook.usd@ + ) + { + float3 xformOp:rotateXYZ = (3.2602853e-7, -0.0000017818304, 85.06888) + float3 xformOp:scale = (0.99999934, 0.9999994, 0.9999994) + double3 xformOp:translate = (35.89625490632731, 116.32287780769308, 162.9712346024937) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "Hook_6" ( + add references = @./assets/Hook/Hook.usd@ + ) + { + float3 xformOp:rotateXYZ = (0.5033598, 0.094759, 104.05882) + float3 xformOp:scale = (0.9999987, 0.9999987, 0.9999986) + double3 xformOp:translate = (28.539117216258962, 116.30896528280229, 162.97132082604747) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "Hook_7" ( + add references = @./assets/Hook/Hook.usd@ + ) + { + float3 xformOp:rotateXYZ = (1.0977578e-7, 0.000001189935, 89.85618) + float3 xformOp:scale = (0.9999994, 0.9999994, 0.9999994) + double3 xformOp:translate = (21.354276749114604, 116.32290199103622, 162.97122934687027) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "GarlicRope_1" ( + add references = @./assets/GarlicRope/GarlicRope.usd@ + ) + { + float3 xformOp:scale = (0.75028867, 0.75028867, 0.75028867) + double3 xformOp:translate = (184.3601697190307, 131.2726027734496, 317.8975084899459) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:scale"] + } + } + + def Xform "SinkArea_grp" ( + kind = "group" + ) + { + def Xform "Cupboard_grp" ( + kind = "group" + ) + { + def "PaperTowelRoll_1" ( + add references = @./assets/PaperTowelRoll/PaperTowelRoll.usd@ + ) + { + double3 xformOp:translate = (-70.07788467407227, 115.28915786743164, 149.6409149169922) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "WallPineapple_1" ( + add references = @./assets/WallPineapple/WallPineapple.usd@ + ) + { + float xformOp:rotateX = -0.36716962 + double3 xformOp:translate = (-161.04129791259768, 34.63547115943115, 147.10012815307812) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateX"] + } + + def Xform "WallFruits_set" ( + kind = "group" + ) + { + float xformOp:rotateZ = -91.85492 + double3 xformOp:translate = (-80.40090560713193, 109.8007661146881, 200.04714965820312) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZ"] + + def Xform "WallApples_grp" ( + kind = "group" + ) + { + def "WallApple_1" ( + add references = @./assets/WallApple/WallApple.usd@ + ) + { + float xformOp:rotateZ = -178.14508 + double3 xformOp:translate = (7.723038442763169, -0.044227170999889154, 8.98358154296875) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZ"] + } + } + + def Xform "WallBanana_grp" ( + kind = "group" + ) + { + def "WallBanana_1" ( + add references = @./assets/WallBanana/WallBanana.usd@ + ) + { + float xformOp:rotateZ = -178.14508 + double3 xformOp:translate = (-0.8832801986556547, -0.028601891860773776, 0) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZ"] + } + } + + def Xform "WallFlower_grp" ( + kind = "group" + ) + { + def "WallFlower_1" ( + add references = @./assets/WallFlower/WallFlower.usd@ + ) + { + float3 xformOp:rotateXYZ = (180, -39.45198, 1.8549194) + double3 xformOp:translate = (0.2833441244187611, 0.10694101457066552, 26.225935725566103) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + } + + def Xform "WallOrange_grp" ( + kind = "group" + ) + { + def "WallOrange_1" ( + add references = @./assets/WallOrange/WallOrange.usd@ + ) + { + float3 xformOp:rotateXYZ = (180, -6.8885755e-15, 1.8549194) + double3 xformOp:translate = (-7.4067806989878875, -0.24759163648944593, 20.703370404666657) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + } + } + + def "BowlA_1" ( + add references = @./assets/Bowl/Bowl.usd@ + variants = { + string modelingVariant = "BowlA" + } + ) + { + float3 xformOp:rotateXYZ = (-2.260768, 0.0000017720444, 8.177297e-7) + float3 xformOp:scale = (0.9999999, 0.9999999, 0.9999999) + double3 xformOp:translate = (-169.2918707241185, 65.31342534224807, 228.92416577449782) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "BowlB_1" ( + add references = @./assets/Bowl/Bowl.usd@ + variants = { + string modelingVariant = "BowlB" + } + ) + { + float xformOp:rotateX = 7.624711 + double3 xformOp:translate = (-169.29197692871097, 66.96917809762255, 233.003346248097) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateX"] + } + + def "BowlC_1" ( + add references = @./assets/Bowl/Bowl.usd@ + variants = { + string modelingVariant = "BowlC" + } + ) + { + float xformOp:rotateX = -9.377107 + double3 xformOp:translate = (-169.29197692871094, 63.139872991934745, 236.92019920248694) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateX"] + } + + def "BowlE_1" ( + add references = @./assets/Bowl/Bowl.usd@ + variants = { + string modelingVariant = "BowlE" + } + ) + { + double3 xformOp:translate = (-116.6874771118164, 116.24128341674805, 229.5704803466797) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "CerealBoxA_1" ( + add references = @./assets/CerealBox/CerealBox.usd@ + variants = { + string modelingVariant = "CerealBoxA" + } + ) + { + float3 xformOp:rotateXYZ = (90.000015, -0.22447143, 180) + float3 xformOp:scale = (0.8662883, 0.8662883, 0.86628824) + double3 xformOp:translate = (-170.18266983412093, 90.96124146711307, 231.84640769637764) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CerealBoxA_2" ( + add references = @./assets/CerealBox/CerealBox.usd@ + variants = { + string modelingVariant = "CerealBoxA" + } + ) + { + float3 xformOp:rotateXYZ = (0.0000055531095, -8.08054e-8, 162.15524) + float3 xformOp:scale = (0.86628747, 0.86628747, 0.86628735) + double3 xformOp:translate = (-170.47325007912988, 87.821097767785, 229.41778052239076) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CerealBoxA_3" ( + add references = @./assets/CerealBox/CerealBox.usd@ + variants = { + string modelingVariant = "CerealBoxA" + } + ) + { + float xformOp:rotateZ = 106.06325 + double3 xformOp:translate = (-149.80998596556412, 112.59352006264382, 229.38143920898438) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZ"] + } + + def "CupA_1" ( + add references = @./assets/Cup/Cup.usd@ + variants = { + string modelingVariant = "CupA" + } + ) + { + float xformOp:rotateZ = -179.364 + double3 xformOp:translate = (-177.2112831514089, 41.52793395078554, 229.72091674804688) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZ"] + } + } + + def Xform "CookingUtensils_grp" ( + kind = "group" + ) + { + def "TinCanB_1" ( + add references = @./assets/TinCan/TinCan.usd@ + variants = { + string modelingVariant = "TinCanB" + } + ) + { + double3 xformOp:translate = (79.15795516967773, 119.5732650756836, 94.22218322753906) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "WoodenSpoonA_1" ( + add references = @./assets/WoodenSpoon/WoodenSpoon.usd@ + variants = { + string modelingVariant = "WoodenSpoonA" + } + ) + { + float3 xformOp:rotateXYZ = (-2.4111772, 3.431232, 64.24712) + double3 xformOp:translate = (74.04588907327975, 120.95225744760991, 100.7874684168008) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "SpoonSpaghetti_1" ( + add references = @./assets/SpoonSpaghetti/SpoonSpaghetti.usd@ + ) + { + float3 xformOp:rotateXYZ = (-21.889322, 2.6026566e-8, 28.634457) + double3 xformOp:translate = (77.0228298466901, 120.53343515945836, 104.01225566181375) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "Whisk_1" ( + add references = @./assets/Whisk/Whisk.usd@ + ) + { + float3 xformOp:rotateXYZ = (-13.169889, -2.2145364, 0.518044) + double3 xformOp:translate = (79.27292866113805, 120.76345469447632, 100.31516845843895) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "WoodenSpoonB_1" ( + add references = @./assets/WoodenSpoon/WoodenSpoon.usd@ + variants = { + string modelingVariant = "WoodenSpoonB" + } + ) + { + float3 xformOp:rotateXYZ = (-16.308596, -0.5110148, -25.801283) + double3 xformOp:translate = (82.33832415609702, 117.82355972055026, 97.02033465833102) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "SpatulaSlotted_1" ( + add references = @./assets/SpatulaSlotted/SpatulaSlotted.usd@ + ) + { + float3 xformOp:rotateXYZ = (-14.772044, 5.495831e-7, 83.07676) + double3 xformOp:translate = (77.00989346003541, 117.90878090371876, 96.10311236538739) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + } + + def Xform "DryingRack_grp" ( + kind = "group" + ) + { + def "WoodenDryingRack_1" ( + add references = @./assets/WoodenDryingRack/WoodenDryingRack.usd@ + ) + { + double3 xformOp:translate = (43.194485664367676, 102.20072174072266, 94.9293212890625) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "PlateBClean_1" ( + add references = @./assets/Plate/Plate.usd@ + variants = { + string modelingVariant = "PlateB" + string shadingVariant = "Clean" + } + ) + { + float3 xformOp:rotateXYZ = (92.64462, 89.660385, 92.729034) + float3 xformOp:scale = (0.9999999, 0.9999999, 0.99999994) + double3 xformOp:translate = (49.04329222152885, 102.69612861009809, 123.73367253316044) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "PlateBClean_2" ( + add references = @./assets/Plate/Plate.usd@ + variants = { + string modelingVariant = "PlateB" + string shadingVariant = "Clean" + } + ) + { + float3 xformOp:rotateXYZ = (-51.756905, 83.27709, -50.595306) + double3 xformOp:translate = (52.437646874789365, 103.107788043942, 123.30549976684166) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "PlateBClean_3" ( + add references = @./assets/Plate/Plate.usd@ + variants = { + string modelingVariant = "PlateB" + string shadingVariant = "Clean" + } + ) + { + float3 xformOp:rotateXYZ = (136.60216, 84.52621, 133.00578) + double3 xformOp:translate = (55.805854176465154, 103.20897836394043, 123.43743415604932) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "PlateBClean_4" ( + add references = @./assets/Plate/Plate.usd@ + variants = { + string modelingVariant = "PlateB" + string shadingVariant = "Clean" + } + ) + { + float3 xformOp:rotateXYZ = (5.4285483, 81.82255, 5.1215773) + float3 xformOp:scale = (0.9999999, 1, 0.9999999) + double3 xformOp:translate = (23.623576177218105, 103.5320976987161, 123.5796890558725) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "PlateBClean_5" ( + add references = @./assets/Plate/Plate.usd@ + variants = { + string modelingVariant = "PlateB" + string shadingVariant = "Clean" + } + ) + { + float3 xformOp:rotateXYZ = (152.36526, 82.290306, 150.7746) + float3 xformOp:scale = (0.9999997, 0.9999998, 0.99999976) + double3 xformOp:translate = (39.53498316086395, 103.16898760456523, 123.49179261834564) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + } + + def Xform "Sink_grp" ( + kind = "group" + ) + { + def "PlateA_2" ( + add references = @./assets/Plate/Plate.usd@ + variants = { + string modelingVariant = "PlateA" + } + ) + { + float3 xformOp:rotateXYZ = (93.40453, -0.37633228, 89.98789) + float3 xformOp:scale = (0.58129203, 0.58129203, 0.58129203) + double3 xformOp:translate = (-72.62255832330561, 91.22948551422215, 90.61996007221754) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "PlateA_1" ( + add references = @./assets/Plate/Plate.usd@ + variants = { + string modelingVariant = "PlateA" + } + ) + { + float3 xformOp:rotateXYZ = (93.40454, -0.37633246, 85.287735) + float3 xformOp:scale = (0.5719971, 0.57199717, 0.57199717) + double3 xformOp:translate = (-70.09403276372682, 91.28437476298885, 90.62006240143359) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "PlateADirty_2" ( + add references = @./assets/Plate/Plate.usd@ + variants = { + string modelingVariant = "PlateA" + string shadingVariant = "Dirty" + } + ) + { + float3 xformOp:rotateXYZ = (93.40453, -0.37633264, 89.98789) + float3 xformOp:scale = (0.9999998, 0.9999999, 0.9999998) + double3 xformOp:translate = (5.0307818914817695, 95.68721330611461, 95.20786313702781) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "PlateAClean_2" ( + add references = @./assets/Plate/Plate.usd@ + variants = { + string modelingVariant = "PlateA" + string shadingVariant = "Clean" + } + ) + { + float3 xformOp:rotateXYZ = (105.22701, -0.36586806, 89.91104) + double3 xformOp:translate = (8.613164412893367, 100.48233688501666, 95.43036934422936) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "BowlF_3" ( + add references = @./assets/Bowl/Bowl.usd@ + variants = { + string modelingVariant = "BowlF" + } + ) + { + float3 xformOp:rotateXYZ = (-1.098436, -0.0000020776492, 4.0507612e-7) + float3 xformOp:scale = (0.5571715, 0.5571716, 0.5571716) + double3 xformOp:translate = (-18.852534030020628, 107.07843350557707, 86.78253888273) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "PlateADirty_1" ( + add references = @./assets/Plate/Plate.usd@ + variants = { + string modelingVariant = "PlateA" + string shadingVariant = "Dirty" + } + ) + { + float3 xformOp:rotateXYZ = (-0.17948349, -0.08122843, 90.13212) + float3 xformOp:scale = (1.0000005, 1.0000005, 1.0000005) + double3 xformOp:translate = (-13.217735362293226, 101.45385085946553, 82.4852251233398) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "PlateAClean_1" ( + add references = @./assets/Plate/Plate.usd@ + variants = { + string modelingVariant = "PlateA" + string shadingVariant = "Clean" + } + ) + { + float3 xformOp:rotateXYZ = (105.145935, -1.8764997, 90.61493) + float3 xformOp:scale = (1.0000001, 1.0000001, 1.0000001) + double3 xformOp:translate = (1.3236542445820714, 102.9578461633308, 95.59617631264337) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CupD_2" ( + add references = @./assets/Cup/Cup.usd@ + variants = { + string modelingVariant = "CupD" + } + ) + { + float3 xformOp:rotateXYZ = (25.419254, -0.03930135, -154.2413) + float3 xformOp:scale = (0.88930357, 0.8893035, 0.8893035) + double3 xformOp:translate = (-16.59223555950731, 91.3088209267378, 85.31557572986357) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "BowlA_3" ( + add references = @./assets/Bowl/Bowl.usd@ + variants = { + string modelingVariant = "BowlA" + } + ) + { + float3 xformOp:rotateXYZ = (0.67464155, 0.000005136389, 0.0000018165883) + float3 xformOp:scale = (0.5788287, 0.57882875, 0.5788288) + double3 xformOp:translate = (-18.82973712534953, 107.79091532852003, 84.26932585358678) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "BowlF_2" ( + add references = @./assets/Bowl/Bowl.usd@ + variants = { + string modelingVariant = "BowlF" + } + ) + { + float3 xformOp:rotateXYZ = (11.368801, -0.0000013420888, 0.0000010392364) + float3 xformOp:scale = (0.57882863, 0.57882863, 0.57882863) + double3 xformOp:translate = (-19.07516935419624, 109.0703721300668, 85.6541486907837) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "PanA_1" ( + add references = @./assets/Pan/Pan.usd@ + variants = { + string modelingVariant = "PanA" + } + ) + { + float3 xformOp:rotateXYZ = (16.176533, 7.5575476, -58.074165) + double3 xformOp:translate = (-51.85874404481002, 104.4314904017038, 91.27351815733066) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "Spatula_1" ( + add references = @./assets/Spatula/Spatula.usd@ + ) + { + float3 xformOp:rotateXYZ = (-108.407364, -16.648685, 88.65047) + double3 xformOp:translate = (-35.873079282167595, 100.0535566116445, 98.9025321084339) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "FlowerPotA_1" ( + add references = @./assets/FlowerPot/FlowerPot.usd@ + variants = { + string modelingVariant = "FlowerPotA" + } + ) + { + float3 xformOp:rotateXYZ = (0.16141465, 18.154362, 0.13177088) + float3 xformOp:scale = (0.7239449, 0.7239449, 0.7239449) + double3 xformOp:translate = (-38.967789919804375, 114.50400292711629, 84.03057992186045) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "BowlF_1" ( + add references = @./assets/Bowl/Bowl.usd@ + variants = { + string modelingVariant = "BowlF" + } + ) + { + float xformOp:rotateX = 8.433404 + double3 xformOp:translate = (-51.725704948318466, 102.75071994755282, 85.87588331739938) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateX"] + } + + def "Knife_1" ( + add references = @./assets/Knife/Knife.usd@ + ) + { + float3 xformOp:rotateXYZ = (48.7628, -5.054806, 46.977013) + float3 xformOp:scale = (0.8902934, 0.89029336, 0.8902933) + double3 xformOp:translate = (-35.534543249087506, 87.26974706635363, 93.9310490815927) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "Spoon_1" ( + add references = @./assets/Spoon/Spoon.usd@ + ) + { + float3 xformOp:rotateXYZ = (-56.832127, 11.529522, -123.91461) + float3 xformOp:scale = (0.9999998, 1, 0.99999994) + double3 xformOp:translate = (-35.39781716332408, 89.82466313245239, 91.83381323071927) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "Spoon_3" ( + add references = @./assets/Spoon/Spoon.usd@ + ) + { + float3 xformOp:rotateXYZ = (-118.27692, -12.602805, 43.061516) + double3 xformOp:translate = (-26.11986891163795, 76.40015636324027, 100.424994951504) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "Spoon_4" ( + add references = @./assets/Spoon/Spoon.usd@ + ) + { + float3 xformOp:rotateXYZ = (59.469124, 7.665527, 31.852) + double3 xformOp:translate = (-38.67507527125072, 89.51551167898694, 94.85544685001052) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "BowlA_2" ( + add references = @./assets/Bowl/Bowl.usd@ + variants = { + string modelingVariant = "BowlA" + } + ) + { + float xformOp:rotateX = -2.2607574 + double3 xformOp:translate = (-52.10125732421875, 101.32071677132356, 81.98733328253292) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateX"] + } + + def "CupD_1" ( + add references = @./assets/Cup/Cup.usd@ + variants = { + string modelingVariant = "CupD" + } + ) + { + float3 xformOp:rotateXYZ = (25.41926, -0.03930623, 42.242737) + double3 xformOp:translate = (-37.757480914114126, 88.81399976027785, 90.61081450392845) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "PlateA_3" ( + add references = @./assets/Plate/Plate.usd@ + variants = { + string modelingVariant = "PlateA" + } + ) + { + float3 xformOp:rotateXYZ = (-20.553246, 40.522614, 75.266205) + float3 xformOp:scale = (0.41812834, 0.41812828, 0.4181283) + double3 xformOp:translate = (-48.028217659278596, 89.06180583123998, 91.42393004175344) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "Spoon_5" ( + add references = @./assets/Spoon/Spoon.usd@ + ) + { + float3 xformOp:rotateXYZ = (15.940988, 1.3882605, -109.69993) + double3 xformOp:translate = (-21.615681126290823, 86.70437191677405, 86.69307247057071) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "FlowerPotA_2" ( + add references = @./assets/FlowerPot/FlowerPot.usd@ + variants = { + string modelingVariant = "FlowerPotA" + } + ) + { + float3 xformOp:rotateXYZ = (-2.1246502, -0.12140877, 0.4456939) + float3 xformOp:scale = (0.7160168, 0.7160169, 0.7160169) + double3 xformOp:translate = (-24.778409185294237, 87.73851816918321, 85.28573779529643) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "FlowerPotA_3" ( + add references = @./assets/FlowerPot/FlowerPot.usd@ + variants = { + string modelingVariant = "FlowerPotA" + } + ) + { + float3 xformOp:rotateXYZ = (177.85939, 84.13455, 175.73874) + float3 xformOp:scale = (0.71592927, 0.71592927, 0.7159292) + double3 xformOp:translate = (-18.339602753596637, 85.66076789001687, 87.12559664098382) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "FlowerPotA_4" ( + add references = @./assets/FlowerPot/FlowerPot.usd@ + variants = { + string modelingVariant = "FlowerPotA" + } + ) + { + float3 xformOp:rotateXYZ = (-0.333121, -0.13912675, 0.44168952) + float3 xformOp:scale = (0.72394484, 0.72394484, 0.72394484) + double3 xformOp:translate = (-24.777410233995212, 87.89325614184341, 82.52486213857824) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "FlowerPotA_6" ( + add references = @./assets/FlowerPot/FlowerPot.usd@ + variants = { + string modelingVariant = "FlowerPotA" + } + ) + { + float3 xformOp:rotateXYZ = (2.0972486, -0.15387617, 0.43507192) + float3 xformOp:scale = (0.71592915, 0.71592915, 0.71592915) + double3 xformOp:translate = (-24.778419501228655, 88.45384992438977, 86.97213033481194) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "Fork_1" ( + add references = @./assets/Fork/Fork.usd@ + ) + { + float3 xformOp:rotateXYZ = (-0.0000011483623, 19.789494, 104.28381) + double3 xformOp:translate = (-25.02534273609303, 86.39461940033627, 88.13145219923406) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "SoapDish_1" ( + add references = @./assets/SoapDish/SoapDish.usd@ + ) + { + double3 xformOp:translate = (-28.498147010803223, 124.42515182495117, 95.08424377441406) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "SoapDispenser_1" ( + add references = @./assets/SoapDispenser/SoapDispenser.usd@ + ) + { + float xformOp:rotateZ = 90 + double3 xformOp:translate = (-76.31252670288086, 125.33702087402345, 94.27871704101562) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZ"] + } + + def "SoapSponge_1" ( + add references = @./assets/SoapSponge/SoapSponge.usd@ + ) + { + float3 xformOp:rotateXYZ = (0.7290543, 18.960032, 2.1384225) + double3 xformOp:translate = (-19.700463182582542, 125.84486138225346, 97.30874794397829) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "HandTowel_1" ( + add references = @./assets/HandTowel/HandTowel.usd@ + ) + { + double3 xformOp:translate = (-52.79067802429199, 76.31832504272461, 74.5525131225586) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + } + + def Xform "Countertop_grp" ( + kind = "group" + ) + { + def "RollingPin_1" ( + add references = @./assets/RollingPin/RollingPin.usd@ + ) + { + float xformOp:rotateZ = 79.94653 + double3 xformOp:translate = (-181.41102787903841, 79.63001284516734, 98.77820540740835) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZ"] + } + + def "BottleSmallGreen_1" ( + add references = @./assets/BottleB/BottleB.usd@ + variants = { + string modelingVariant = "Small" + string shadingVariant = "Green" + } + ) + { + float3 xformOp:rotateXYZ = (1.7203475, 0.00000721066, 0) + float3 xformOp:scale = (0.93035305, 0.930353, 0.930353) + double3 xformOp:translate = (-183.33647852599088, 100.84477666462531, 95.94794063637165) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "BottleSmallBrown_1" ( + add references = @./assets/BottleB/BottleB.usd@ + variants = { + string modelingVariant = "Small" + string shadingVariant = "Brown" + } + ) + { + double3 xformOp:translate = (-183.4407501220703, 107.72176742553711, 95.82771301269531) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "BottleLargeGreen_1" ( + add references = @./assets/BottleB/BottleB.usd@ + variants = { + string modelingVariant = "Large" + string shadingVariant = "Green" + } + ) + { + double3 xformOp:translate = (-178.21047973632812, 119.49094772338867, 94.74855041503906) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Mixer_1" ( + add references = @./assets/Mixer/Mixer.usd@ + ) + { + double3 xformOp:translate = (-157.29100482544493, 105.24040306132294, 94.20210638717005) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Toaster_1" ( + add references = @./assets/Toaster/Toaster.usd@ + ) + { + double3 xformOp:translate = (-113.70754623413086, 120.20833587646484, 94.24053192138672) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "MeasuringCup_1" ( + add references = @./assets/MeasuringCup/MeasuringCup.usd@ + ) + { + float xformOp:rotateZ = -27.228394 + double3 xformOp:translate = (-130.9367387071652, 85.84912623111103, 93.99273681640625) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZ"] + } + + def "PotA_1" ( + add references = @./assets/Pot/Pot.usd@ + variants = { + string modelingVariant = "PotA" + } + ) + { + double3 xformOp:translate = (-84.04708480834961, 105.22087860107422, 94.3669204711914) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Knife_2" ( + add references = @./assets/Knife/Knife.usd@ + ) + { + float3 xformOp:rotateXYZ = (-97.31077, 0.41646004, 28.397) + double3 xformOp:translate = (-80.17791610454488, 97.66358517966985, 104.89065058750286) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + } + + def Xform "SinkFloor_grp" ( + kind = "group" + ) + { + def "BottleMediumNoCap_1" ( + add references = @./assets/BottleB/BottleB.usd@ + variants = { + string modelingVariant = "MediumNoCap" + } + ) + { + float3 xformOp:scale = (0.99999905, 0.99999905, 0.99999905) + double3 xformOp:translate = (-18.57214105473922, 111.74085287251438, 0.22535331738425693) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:scale"] + } + + def "BottleMediumNoCap_2" ( + add references = @./assets/BottleB/BottleB.usd@ + variants = { + string modelingVariant = "MediumNoCap" + } + ) + { + float xformOp:rotateY = 0.0000016951275 + float3 xformOp:scale = (1.0475875, 1.0475875, 1.0475875) + double3 xformOp:translate = (3.925093749111184, 111.74085798977482, -0.5610677535349764) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateY", "xformOp:scale"] + } + + def "BottleMediumNoCap_3" ( + add references = @./assets/BottleB/BottleB.usd@ + variants = { + string modelingVariant = "MediumNoCap" + } + ) + { + double3 xformOp:translate = (-82.2597427368164, 91.77927780151367, 0.22533893585205078) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "BottleMediumNoCap_4" ( + add references = @./assets/BottleB/BottleB.usd@ + variants = { + string modelingVariant = "MediumNoCap" + } + ) + { + float3 xformOp:scale = (0.99999905, 0.99999905, 0.99999905) + double3 xformOp:translate = (-76.37472301609674, 106.76448858697941, 0.2253545327448989) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:scale"] + } + + def "BottleMediumNoCap_5" ( + add references = @./assets/BottleB/BottleB.usd@ + variants = { + string modelingVariant = "MediumNoCap" + } + ) + { + float3 xformOp:scale = (1.0475875, 1.0475875, 1.0475875) + double3 xformOp:translate = (-53.877515013623466, 106.76449361470657, -0.561067935091679) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:scale"] + } + + def "BottleMediumNoCap_6" ( + add references = @./assets/BottleB/BottleB.usd@ + variants = { + string modelingVariant = "MediumNoCap" + } + ) + { + float xformOp:rotateX = 0.0000022998067 + float3 xformOp:scale = (0.99999905, 0.99999905, 0.99999905) + double3 xformOp:translate = (-24.457135903503016, 96.75569935896242, 0.22535310617960544) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateX", "xformOp:scale"] + } + + def "StoolWooden_1" ( + add references = @./assets/StoolWooden/StoolWooden.usd@ + ) + { + double3 xformOp:translate = (-32.902894020080566, 47.302985191345215, 1.1144332885742188) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Rug_1" ( + add references = @./assets/Rug/Rug.usd@ + ) + { + double3 xformOp:translate = (-28.399791717529297, 35.212817430496216, -1.0039896965026855) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + } + + def "FlowerPotB_1" ( + add references = @./assets/FlowerPot/FlowerPot.usd@ + variants = { + string modelingVariant = "FlowerPotB" + } + ) + { + double3 xformOp:translate = (-57.1489200592041, 150.47003936767578, 140.59075927734375) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "CupCBlue_2" ( + add references = @./assets/Cup/Cup.usd@ + variants = { + string modelingVariant = "CupC" + string shadingVariant = "Blue" + } + ) + { + float3 xformOp:rotateXYZ = (-0.000006214445, 0.0000065051977, 102.09888) + float3 xformOp:scale = (0.80481434, 0.8048143, 0.80481434) + double3 xformOp:translate = (59.85412881033615, 80.15379604478221, 94.18969759073717) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "Clock_1" ( + add references = @./assets/Clock/Clock.usd@ + ) + { + float xformOp:rotateZ = 49.0839 + double3 xformOp:translate = (77.80624364639014, 99.57145142773278, 94.75929260253906) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZ"] + } + } + + def Xform "StoveArea_grp" ( + kind = "group" + ) + { + def "Stove_1" ( + add references = @./assets/Stove/Stove.usd@ + ) + { + double3 xformOp:translate = (148.024169921875, 127.69548225402832, 0.0048828125) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "TeaKettle_1" ( + add references = @./assets/TeaKettle/TeaKettle.usd@ + ) + { + float xformOp:rotateZ = -23.581776 + double3 xformOp:translate = (166.65962396920366, 110.77507538613483, 97.51437377929688) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZ"] + } + + def "Broom_1" ( + add references = @./assets/Broom/Broom.usd@ + ) + { + float3 xformOp:rotateXYZ = (-24.30863, -9.107902, -1.6604284) + double3 xformOp:translate = (104.76921939333599, 77.60719275527728, 5.695303026470224) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "DustPan_1" ( + add references = @./assets/DustPan/DustPan.usd@ + ) + { + float3 xformOp:rotateXYZ = (75.19409, 0.14854926, 90.49442) + double3 xformOp:translate = (87.12747373810807, 95.75077948955378, 24.529990970589857) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + } + + def Xform "FridgeArea_grp" ( + kind = "group" + ) + { + def "Refridgerator_1" ( + add references = @./assets/Refridgerator/Refridgerator.usd@ + ) + { + double3 xformOp:translate = (259.9341506958008, 95.84612274169922, -0.5277154445648193) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "CerealBoxB_1" ( + add references = @./assets/CerealBox/CerealBox.usd@ + variants = { + string modelingVariant = "CerealBoxB" + } + ) + { + float3 xformOp:rotateXYZ = (0.35271502, -0.35731176, 55.953945) + float3 xformOp:scale = (0.98998296, 0.989983, 0.98998296) + double3 xformOp:translate = (251.8166174091176, 88.57795598495771, 188.26784434749862) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CerealBoxB_2" ( + add references = @./assets/CerealBox/CerealBox.usd@ + variants = { + string modelingVariant = "CerealBoxB" + } + ) + { + float xformOp:rotateZ = -98.97049 + double3 xformOp:translate = (234.66953663723456, 88.570938705161, 188.2814483642578) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZ"] + } + } + } + + def Xform "West_grp" ( + kind = "group" + ) + { + def Xform "WestWall_grp" ( + kind = "group" + ) + { + def "PaperLarge_1" ( + add references = @./assets/PaperLarge/PaperLarge.usd@ + ) + { + float xformOp:rotateZ = 88.847855 + double3 xformOp:translate = (-177.2756023410839, -67.92375949880099, 205.54920959472656) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZ"] + } + + def "PaperSmall_1" ( + add references = @./assets/PaperSmall/PaperSmall.usd@ + ) + { + float xformOp:rotateZ = -90.331566 + double3 xformOp:translate = (-187.84706878674882, -146.36038212422855, 226.25355529785156) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZ"] + } + + def "ShellSmall_1" ( + add references = @./assets/ShellSmall/ShellSmall.usd@ + ) + { + float3 xformOp:rotateXYZ = (0.000001137453, 23.0389, 89.286964) + double3 xformOp:translate = (-177.260858542665, -18.956741906740195, 199.3251196444826) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "ShellSmall_2" ( + add references = @./assets/ShellSmall/ShellSmall.usd@ + ) + { + float3 xformOp:rotateXYZ = (0.9196024, -33.332745, 89.2089) + float3 xformOp:scale = (0.6503209, 0.65032077, 0.65032077) + double3 xformOp:translate = (-177.43748870134417, -25.9547855682346, 207.2962526008918) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "FramePictureB_1" ( + add references = @./assets/FramePicture/FramePicture.usd@ + variants = { + string modelingVariant = "FramePictureB" + } + ) + { + float3 xformOp:rotateXYZ = (-3.7499948, 2.596389, -90.5484) + double3 xformOp:translate = (-175.7610261594479, -123.48839987330913, 210.26970505647526) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "FramePictureD_1" ( + add references = @./assets/FramePicture/FramePicture.usd@ + variants = { + string modelingVariant = "FramePictureD" + } + ) + { + float xformOp:rotateZ = 90 + double3 xformOp:translate = (-186.01227027133578, -28.329116821289077, 219.46180725097656) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZ"] + } + + def "FramePictureOval_1" ( + add references = @./assets/FramePictureOval/FramePictureOval.usd@ + ) + { + float3 xformOp:rotateXYZ = (2.9880314, 0.01628757, 89.68797) + double3 xformOp:translate = (-178.15198919477302, -97.36443288494881, 209.97915868248623) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + } + + def Xform "FoldingTable_grp" ( + kind = "group" + ) + { + def "FoldingTable_1" ( + add references = @./assets/FoldingTable/FoldingTable.usd@ + ) + { + double3 xformOp:translate = (-150.1519012451172, -78.98514080047607, 0.10723477602005005) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "BookBlue_1" ( + add references = @./assets/Book/Book.usd@ + variants = { + string shadingVariant = "BookBlue" + } + ) + { + float xformOp:rotateZ = 123.6851 + double3 xformOp:translate = (-149.21710945646072, -83.18015628979177, 95.5684814453125) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZ"] + } + + def "BookGreen_1" ( + add references = @./assets/Book/Book.usd@ + variants = { + string shadingVariant = "BookGreen" + } + ) + { + float3 xformOp:rotateXYZ = (-9.723859, 69.35383, 79.63052) + float3 xformOp:scale = (0.53299946, 0.5329995, 0.53299946) + double3 xformOp:translate = (-154.26723581639231, -62.17959290405879, 104.95475855551783) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "BookGreen_2" ( + add references = @./assets/Book/Book.usd@ + variants = { + string shadingVariant = "BookGreen" + } + ) + { + float3 xformOp:rotateXYZ = (0.005831081, -0.00028499414, 146.2728) + float3 xformOp:scale = (0.74229425, 0.7422943, 0.74229425) + double3 xformOp:translate = (-150.8052770040327, -81.62522162938637, 99.66055211222924) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "BookTan_1" ( + add references = @./assets/Book/Book.usd@ + variants = { + string shadingVariant = "BookTan" + } + ) + { + float3 xformOp:rotateXYZ = (-9.711233, 69.35077, 79.632065) + float3 xformOp:scale = (0.4647244, 0.46472445, 0.46472442) + double3 xformOp:translate = (-154.65234272072377, -58.59481772636869, 103.60227884043604) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "BookTan_2" ( + add references = @./assets/Book/Book.usd@ + variants = { + string shadingVariant = "BookTan" + } + ) + { + float3 xformOp:rotateXYZ = (-0.0074490705, 0.0034164505, 104.45887) + float3 xformOp:scale = (0.7468428, 0.74684274, 0.74684274) + double3 xformOp:translate = (-148.9312196988248, -84.17855064189362, 103.20634972066463) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "BreadBag_1" ( + add references = @./assets/BreadBag/BreadBag.usd@ + ) + { + float xformOp:rotateZ = 129.22975 + double3 xformOp:translate = (-146.43432617187503, -87.77270507812504, 106.24114990234375) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZ"] + } + + def "HangerLightBrownDirty_1" ( + add references = @./assets/Hanger/Hanger.usd@ + variants = { + string shadingVariant = "LightBrownDirty" + } + ) + { + float3 xformOp:rotateXYZ = (88.97368, 0.71139795, -4.4926605) + float3 xformOp:scale = (0.999999, 0.9999989, 0.999999) + double3 xformOp:translate = (-143.3698092350318, -118.47038856570867, 96.26506081277736) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "HangerLightBrown_2" ( + add references = @./assets/Hanger/Hanger.usd@ + variants = { + string shadingVariant = "LightBrown" + } + ) + { + float3 xformOp:rotateXYZ = (88.64532, 0.9125623, -20.654312) + float3 xformOp:scale = (0.9999996, 0.99999964, 0.9999995) + double3 xformOp:translate = (-145.5503384931136, -117.32740781493882, 97.88546618319062) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "HangerLightBrownDirty_2" ( + add references = @./assets/Hanger/Hanger.usd@ + variants = { + string shadingVariant = "LightBrownDirty" + } + ) + { + float3 xformOp:rotateXYZ = (-81.34504, 5.311067, -39.198544) + float3 xformOp:scale = (0.99999964, 0.99999946, 0.9999996) + double3 xformOp:translate = (-137.68300264039948, -97.36567285865713, 101.77893651011394) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "HangerLightBrown_3" ( + add references = @./assets/Hanger/Hanger.usd@ + variants = { + string shadingVariant = "LightBrown" + } + ) + { + float3 xformOp:rotateXYZ = (-91.89899, 0.34442022, 117.12441) + float3 xformOp:scale = (0.9999995, 0.9999995, 0.9999996) + double3 xformOp:translate = (-157.02549959932702, -51.1949992076547, 96.19638966509274) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "HangerLightBrownDirty_3" ( + add references = @./assets/Hanger/Hanger.usd@ + variants = { + string shadingVariant = "LightBrownDirty" + } + ) + { + float3 xformOp:rotateXYZ = (-91.89897, 0.34442174, 15.796411) + float3 xformOp:scale = (0.9999994, 0.99999946, 0.99999934) + double3 xformOp:translate = (-152.1954232017468, -30.172332440813022, 97.12940987946226) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "Iron_1" ( + add references = @./assets/Iron/Iron.usd@ + ) + { + float xformOp:rotateZ = 38.14875 + double3 xformOp:translate = (-152.93742141139273, -119.04755027517433, 95.4252046756126) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZ"] + } + } + + def "PaperBagCrumpled_1" ( + add references = @./assets/PaperBagCrumpled/PaperBagCrumpled.usd@ + ) + { + float xformOp:rotateZ = -68.49362 + double3 xformOp:translate = (-148.70739444214573, -15.160889960635089, -0.13477152585983276) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZ"] + } + + def "ShellLarge_1" ( + add references = @./assets/ShellLarge/ShellLarge.usd@ + ) + { + float3 xformOp:rotateXYZ = (6.1738715, 2.2817976e-7, -159.0529) + double3 xformOp:translate = (-138.68504917562387, 30.104790186737972, 85.17193603515624) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "SteamCooker_1" ( + add references = @./assets/SteamCooker/SteamCooker.usd@ + ) + { + double3 xformOp:translate = (-141.6140899658203, 28.00109577178955, -0.2906346321105957) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "StoolMetalWire_1" ( + add references = @./assets/StoolMetalWire/StoolMetalWire.usd@ + ) + { + double3 xformOp:translate = (-139.13666534423828, 27.60222625732422, -0.37734347581863403) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "TinCanA_1" ( + add references = @./assets/TinCan/TinCan.usd@ + variants = { + string modelingVariant = "TinCanA" + } + ) + { + float xformOp:rotateX = -10.259284 + double3 xformOp:translate = (-143.2407913208008, -23.24610853862792, 27.889798606189498) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateX"] + } + + def "TinCanA_2" ( + add references = @./assets/TinCan/TinCan.usd@ + variants = { + string modelingVariant = "TinCanA" + } + ) + { + float3 xformOp:rotateXYZ = (-10.25928, 0.0000015024416, -2.5012895e-7) + float3 xformOp:scale = (0.7477359, 0.7477359, 0.7477359) + double3 xformOp:translate = (-154.2878407651822, -22.861860728183572, 33.542663196630386) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "BottleTall_1" ( + add references = @./assets/Bottle/Bottle.usd@ + variants = { + string modelingVariant = "Tall" + } + ) + { + float xformOp:rotateY = -11.467299 + double3 xformOp:translate = (-147.76688599955608, -11.381963491439818, 28.336762179616663) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateY"] + } + + def "HangerLightBrown_1" ( + add references = @./assets/Hanger/Hanger.usd@ + variants = { + string shadingVariant = "LightBrown" + } + ) + { + float3 xformOp:rotateXYZ = (22.4529, -0.3721054, -89.79036) + double3 xformOp:translate = (-166.2041650808777, -144.08153179555686, 97.94837588321613) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "IronBoard_1" ( + add references = @./assets/IronBoard/IronBoard.usd@ + ) + { + float3 xformOp:rotateXYZ = (12.122619, -2.0949277e-7, -89.9981) + double3 xformOp:translate = (-144.7094821967537, -157.64726316897014, 0.36965224936505) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "Ball_1" ( + add references = @./assets/Ball/Ball.usd@ + ) + { + double3 xformOp:translate = (-129.55568313598633, 63.823883056640625, -0.39934539794921875) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + } + + def Xform "DiningTable_grp" ( + kind = "group" + ) + { + def "KitchenTable_1" ( + add references = @./assets/KitchenTable/KitchenTable.usd@ + ) + { + double3 xformOp:translate = (148.60921478271484, -165.71975326538086, -0.1450519561767578) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "ChairB_1" ( + add references = @./assets/Chair/Chair.usd@ + variants = { + string modelingVariant = "ChairB" + } + ) + { + float xformOp:rotateZ = -90 + double3 xformOp:translate = (248.5593185424805, -185.18944549560547, -0.6316165924072266) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZ"] + } + + def "ChairB_2" ( + add references = @./assets/Chair/Chair.usd@ + variants = { + string modelingVariant = "ChairB" + } + ) + { + float xformOp:rotateZ = 106.02446 + double3 xformOp:translate = (43.80702084011234, -178.9814647348254, -0.6316165924072266) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZ"] + } + + def Xform "TableTop_grp" ( + kind = "group" + ) + { + def "Spoon_2" ( + add references = @./assets/Spoon/Spoon.usd@ + ) + { + float3 xformOp:rotateXYZ = (-83.86307, 0.3997105, -110.561905) + float3 xformOp:scale = (1.2283248, 1.2283249, 1.228325) + double3 xformOp:translate = (77.07745969620697, -190.59299188541576, 79.38568761722087) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CupCRed_1" ( + add references = @./assets/Cup/Cup.usd@ + variants = { + string modelingVariant = "CupC" + string shadingVariant = "Red" + } + ) + { + float xformOp:rotateZ = -10.49674 + double3 xformOp:translate = (205.0607282567559, -128.6939211923562, 80.39984130859375) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZ"] + } + + def "FlowerPotA_5" ( + add references = @./assets/FlowerPot/FlowerPot.usd@ + variants = { + string modelingVariant = "FlowerPotA" + } + ) + { + double3 xformOp:translate = (101.34794616699219, -205.65573120117188, 80.25997924804688) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "PaperWrinkle_1" ( + add references = @./assets/PaperWrinkle/PaperWrinkle.usd@ + ) + { + float3 xformOp:rotateXYZ = (-1.4417497, 0.237114, -10.549693) + float3 xformOp:scale = (0.99875855, 0.9987587, 0.9987586) + double3 xformOp:translate = (136.57112153618016, -199.2845509793214, 80.61248241697072) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "PaperWrinkle_2" ( + add references = @./assets/PaperWrinkle/PaperWrinkle.usd@ + ) + { + float3 xformOp:rotateXYZ = (0.39943326, 0.009346967, -10.419863) + float3 xformOp:scale = (0.9959582, 0.99595803, 0.99595803) + double3 xformOp:translate = (136.51481486787594, -152.98690761324173, 80.83227934073217) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "PaperWrinkle_3" ( + add references = @./assets/PaperWrinkle/PaperWrinkle.usd@ + ) + { + float xformOp:rotateZ = 12.494657 + double3 xformOp:translate = (136.6237030029297, -138.14813232421875, 80.61002863121875) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZ"] + } + + def "CrayonWornYellow_1" ( + add references = @./assets/Crayon/Crayon.usd@ + variants = { + string modelingVariant = "CrayonWorn" + string shadingVariant = "Yellow" + } + ) + { + float3 xformOp:rotateXYZ = (54.26125, -89.95773, -0.0035140729) + double3 xformOp:translate = (99.80536272862635, -179.16734555181176, 82.01728874138536) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "CrayonGreen_1" ( + add references = @./assets/Crayon/Crayon.usd@ + variants = { + string modelingVariant = "Crayon" + string shadingVariant = "Green" + } + ) + { + float3 xformOp:rotateXYZ = (-89.50182, -0.050845064, -71.16576) + double3 xformOp:translate = (83.69487233760884, -118.84445717518918, 81.23173034457133) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "CrayonGreen_2" ( + add references = @./assets/Crayon/Crayon.usd@ + variants = { + string modelingVariant = "Crayon" + string shadingVariant = "Green" + } + ) + { + float3 xformOp:rotateXYZ = (-90.28176, 70.60877, -61.356693) + double3 xformOp:translate = (95.38797874849638, -168.80800206393835, 82.08094619133367) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "CrayonPurple_1" ( + add references = @./assets/Crayon/Crayon.usd@ + variants = { + string modelingVariant = "Crayon" + string shadingVariant = "Purple" + } + ) + { + float3 xformOp:rotateXYZ = (92.88714, 1.2185737, 48.786022) + float3 xformOp:scale = (0.999999, 0.99999905, 0.99999905) + double3 xformOp:translate = (76.33279325292787, -137.67949219566273, 81.39452089465155) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CrayonBlue_1" ( + add references = @./assets/Crayon/Crayon.usd@ + variants = { + string modelingVariant = "Crayon" + string shadingVariant = "Blue" + } + ) + { + float xformOp:rotateX = 90.08507 + double3 xformOp:translate = (99.79273986816408, -129.10240019937885, 81.14916679643952) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateX"] + } + + def "CrayonRed_1" ( + add references = @./assets/Crayon/Crayon.usd@ + variants = { + string modelingVariant = "Crayon" + string shadingVariant = "Red" + } + ) + { + float3 xformOp:rotateXYZ = (-131.4959, -89.55903, 179.13725) + double3 xformOp:translate = (115.79199801365063, -179.3240959163633, 81.24872727072952) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "CrayonWornRed_1" ( + add references = @./assets/Crayon/Crayon.usd@ + variants = { + string modelingVariant = "CrayonWorn" + string shadingVariant = "Red" + } + ) + { + float3 xformOp:rotateXYZ = (-94.1097, -81.41502, -72.473526) + float3 xformOp:scale = (1.024841, 1.024841, 1.024841) + double3 xformOp:translate = (83.63364112131843, -115.84040401344072, 81.22699989567604) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CrayonWornOrange_1" ( + add references = @./assets/Crayon/Crayon.usd@ + variants = { + string modelingVariant = "CrayonWorn" + string shadingVariant = "Orange" + } + ) + { + float3 xformOp:rotateXYZ = (-94.1097, -81.41502, -97.90343) + double3 xformOp:translate = (80.68927711233857, -120.29163108507254, 81.2283823401875) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "DinnerMat_1" ( + add references = @./assets/DinnerMat/DinnerMat.usd@ + ) + { + float xformOp:rotateZ = 90 + double3 xformOp:translate = (89.14794921875, -178.21272277832034, 80.48756408691406) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZ"] + } + + def Xform "CerealBowl_grp" ( + kind = "group" + ) + { + def Xform "Cheerios_grp" ( + kind = "group" + ) + { + def "CheerioA_18" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (139.0311, 63.197887, -115.37253) + float3 xformOp:scale = (1.006651, 1.006651, 1.0066512) + double3 xformOp:translate = (88.96037141821432, -174.07215249540957, 92.09292659155898) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_63" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (89.034386, -51.03602, -50.200596) + float3 xformOp:scale = (1.0066507, 1.0066504, 1.0066506) + double3 xformOp:translate = (86.42924240079454, -176.92464570869208, 91.78477168154726) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_9" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (-160.39713, -68.67801, -102.09152) + float3 xformOp:scale = (1.0000002, 1.0000001, 1.0000002) + double3 xformOp:translate = (84.30388797288248, -185.8668938783921, 92.17041069320459) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_43" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (-48.030052, 15.0414295, -27.679485) + float3 xformOp:scale = (1.0000008, 1.0000008, 1.000001) + double3 xformOp:translate = (78.07993977822073, -183.41877108132377, 91.38563869315848) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_1" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (0.13162372, 14.097052, 90.82335) + float3 xformOp:scale = (1.0066508, 1.0066509, 1.0066509) + double3 xformOp:translate = (95.75720033318657, -175.2844502160082, 88.315401493587) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_2" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-7.251368, -2.9016087, 17.080624) + float3 xformOp:scale = (1.0066508, 1.0066508, 1.0066508) + double3 xformOp:translate = (92.49189796045934, -183.00945816918173, 88.38653799499991) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_5" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-101.133385, -55.48367, 90.10697) + float3 xformOp:scale = (1.0331544, 1.0331542, 1.0331544) + double3 xformOp:translate = (95.49456502454024, -184.48076003271134, 87.99190883437626) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_14" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-171.82907, 5.287086, 142.36617) + float3 xformOp:scale = (1.0066499, 1.00665, 1.00665) + double3 xformOp:translate = (79.1567554817295, -180.54158666504696, 89.32273816746618) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_19" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-35.307247, -40.370975, 27.677526) + float3 xformOp:scale = (0.99999887, 0.99999887, 0.9999989) + double3 xformOp:translate = (87.78346565541702, -171.14067000440474, 88.60693925293685) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_22" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-97.38754, -21.293818, 82.638084) + float3 xformOp:scale = (0.9999988, 0.9999988, 0.99999887) + double3 xformOp:translate = (88.93928251710115, -171.2928964687236, 88.30154426782366) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_32" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-97.38755, -21.293829, 82.63808) + float3 xformOp:scale = (0.9999993, 0.9999993, 0.9999993) + double3 xformOp:translate = (88.93928585959677, -170.62302833872886, 89.70517246923032) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_42" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-7.2513647, -2.9015877, 17.080622) + float3 xformOp:scale = (1.0066506, 1.0066508, 1.0066507) + double3 xformOp:translate = (97.06284020161505, -183.7536584835092, 89.14812186165352) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_47" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (15.332734, -72.510506, 1.445429) + float3 xformOp:scale = (1.0066514, 1.0066514, 1.0066514) + double3 xformOp:translate = (91.1791639718663, -176.3255877589053, 89.6148333241481) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_49" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-68.79762, -47.284016, 71.27214) + float3 xformOp:scale = (1.0331541, 1.033154, 1.033154) + double3 xformOp:translate = (94.56866505600036, -184.14424303420668, 88.55614782336971) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_54" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-53.708233, -52.53302, 71.926125) + float3 xformOp:scale = (1.0066496, 1.0066496, 1.0066497) + double3 xformOp:translate = (95.2022723445007, -181.81429507076172, 88.5015972906042) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_62" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-76.95607, -48.66148, 75.12288) + float3 xformOp:scale = (1.0331553, 1.0331553, 1.0331553) + double3 xformOp:translate = (91.98011589034914, -183.7914938948347, 88.53575756969144) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_64" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (57.639874, -61.68762, -44.997536) + float3 xformOp:scale = (0.99999964, 0.9999996, 0.99999946) + double3 xformOp:translate = (86.82555394001963, -170.5863193970839, 89.65777189453676) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_71" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-1.0426416, 5.0394745, 18.1674) + float3 xformOp:scale = (1.006651, 1.006651, 1.006651) + double3 xformOp:translate = (89.3244748199952, -176.80705484374494, 89.445212363309) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_75" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (10.44982, 52.847088, 88.19583) + float3 xformOp:scale = (0.99999934, 0.9999993, 0.9999993) + double3 xformOp:translate = (82.80069343410389, -175.5861461598464, 88.97901571498448) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_77" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-53.708218, -52.53301, 71.92612) + float3 xformOp:scale = (1.0066496, 1.0066497, 1.0066496) + double3 xformOp:translate = (81.05291185433435, -180.35505747049092, 88.68970259874663) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_80" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-97.38754, -21.293818, 82.638084) + float3 xformOp:scale = (0.99999887, 0.99999887, 0.9999989) + double3 xformOp:translate = (91.31489288710515, -173.33550627174404, 87.9568844200526) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_86" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (0.13161683, 14.097052, 90.82335) + float3 xformOp:scale = (1.0066508, 1.0066508, 1.0066508) + double3 xformOp:translate = (96.13990002600517, -180.79156215208542, 88.31541021279625) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_88" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-171.82909, 5.287092, 142.36617) + float3 xformOp:scale = (1.0066502, 1.0066501, 1.0066502) + double3 xformOp:translate = (91.92755630098745, -181.42870849617105, 89.05580547340341) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_91" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-1.0426441, 5.0394793, 18.167395) + float3 xformOp:scale = (1.0066509, 1.0066509, 1.0066509) + double3 xformOp:translate = (88.67761516125194, -181.39413056230208, 88.5826223920593) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_92" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (10.449821, 52.847095, 88.19584) + float3 xformOp:scale = (0.9999993, 0.9999993, 0.9999993) + double3 xformOp:translate = (85.05260574652382, -173.75506896804094, 90.10643390051517) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_93" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-68.79765, -47.284016, 71.27215) + float3 xformOp:scale = (1.0331538, 1.0331539, 1.0331539) + double3 xformOp:translate = (93.19007631384031, -183.5721984067542, 88.47729776027955) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_95" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (15.3326845, -72.5105, 1.445458) + float3 xformOp:scale = (1.0066509, 1.0066509, 1.0066508) + double3 xformOp:translate = (94.41622965107993, -181.13950996768716, 87.63491573779775) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_96" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-93.353584, 25.219875, 68.56581) + float3 xformOp:scale = (0.9999996, 0.9999994, 0.9999995) + double3 xformOp:translate = (87.65371969916686, -172.76769375755325, 90.48789290342475) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_100" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (10.436478, -49.328167, 2.6019113) + double3 xformOp:translate = (89.59764090401302, -178.48859784842753, 89.28824356140024) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "CheerioA_104" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-10.261749, -3.2115846, 93.89053) + float3 xformOp:scale = (1.0066506, 1.0066507, 1.0066506) + double3 xformOp:translate = (95.8979569990405, -181.4187424774507, 89.25719859846848) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_106" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-7.251367, -2.9016006, 17.080624) + float3 xformOp:scale = (1.0066506, 1.0066506, 1.0066506) + double3 xformOp:translate = (95.38512307740078, -175.8613370493233, 87.52605153000894) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_109" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-7.2513595, -2.9015927, 17.080622) + float3 xformOp:scale = (1.0066508, 1.0066508, 1.0066508) + double3 xformOp:translate = (95.76779275106747, -181.3684596824462, 87.52604773969486) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_112" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-101.133385, -55.48367, 90.10697) + float3 xformOp:scale = (1.0331544, 1.0331544, 1.0331545) + double3 xformOp:translate = (94.1159785123947, -183.9086665828964, 87.91306595089435) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_114" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-76.956085, -48.661484, 75.12288) + float3 xformOp:scale = (1.0331553, 1.0331553, 1.0331553) + double3 xformOp:translate = (91.59749466583352, -178.2843733992196, 88.53574699150516) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_118" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-70.75669, 6.72467, 70.71984) + float3 xformOp:scale = (0.999999, 0.99999905, 0.99999905) + double3 xformOp:translate = (83.35003034440054, -172.78799750651703, 89.17327351706933) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_120" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-171.82909, 5.2871003, 142.36617) + float3 xformOp:scale = (1.0066503, 1.0066502, 1.0066502) + double3 xformOp:translate = (91.544891030001, -175.92169512355426, 89.05581697614213) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_123" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-8.757396, -1.2438946, 6.064438) + float3 xformOp:scale = (1.0066506, 1.0066507, 1.0066507) + double3 xformOp:translate = (90.41502257382217, -175.88086916922762, 87.50690874813068) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_124" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-113.703255, 7.7477694, 117.54717) + float3 xformOp:scale = (0.9999994, 0.99999946, 0.9999994) + double3 xformOp:translate = (82.59155484307658, -173.45862881601897, 89.42100992158612) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_129" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (15.3326845, -72.51049, 1.4454765) + float3 xformOp:scale = (1.006651, 1.0066512, 1.0066512) + double3 xformOp:translate = (94.03361148530375, -175.63236515358201, 87.63491511514712) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_131" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (164.66432, -42.71358, 172.91394) + float3 xformOp:scale = (0.9999989, 0.99999887, 0.9999989) + double3 xformOp:translate = (94.19019110003518, -174.44992214129496, 89.60222057674149) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_132" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-93.35359, 25.219877, 68.5658) + float3 xformOp:scale = (0.9999995, 0.9999995, 0.9999996) + double3 xformOp:translate = (85.40177891872702, -174.598712650222, 89.36047705033751) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_135" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-53.708233, -52.533016, 71.92612) + float3 xformOp:scale = (1.0066494, 1.0066495, 1.0066496) + double3 xformOp:translate = (93.44102590311392, -175.7351275744919, 88.42276165001937) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_136" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-35.307224, -40.370968, 27.67745) + float3 xformOp:scale = (0.99999845, 0.99999845, 0.99999857) + double3 xformOp:translate = (90.15903945772801, -173.18325147544292, 88.2622730641682) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_146" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-133.12296, 9.093652, 132.34068) + float3 xformOp:scale = (1.0066513, 1.0066513, 1.0066513) + double3 xformOp:translate = (81.2457265461122, -180.6269061920045, 89.07006504005608) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_148" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-11.086511, -4.5810113, 65.102) + float3 xformOp:scale = (1.0066499, 1.0066497, 1.0066496) + double3 xformOp:translate = (85.18860018514371, -179.77096897814477, 88.69155075298605) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_155" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (0.13162078, 14.097062, 90.82334) + float3 xformOp:scale = (1.0066509, 1.0066509, 1.0066509) + double3 xformOp:translate = (92.86399865333988, -182.43252354463036, 89.17584918150072) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_157" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-125.974945, -7.646117, 40.672737) + float3 xformOp:scale = (1.0066512, 1.006651, 1.0066509) + double3 xformOp:translate = (79.99691513562627, -174.09806493870133, 89.45500031940293) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_167" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-7.251364, -2.9015882, 17.080622) + float3 xformOp:scale = (1.0066508, 1.0066508, 1.0066507) + double3 xformOp:translate = (96.08332428038375, -180.24275974641267, 89.50602818214543) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_5" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (8.203118, 6.5907598, 47.11561) + float3 xformOp:scale = (0.9999998, 0.99999976, 0.99999976) + double3 xformOp:translate = (87.60136109192916, -185.17445118884137, 89.49128576415656) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_11" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (177.24445, -1.1251233, 168.7314) + float3 xformOp:scale = (0.9999992, 0.99999917, 0.99999917) + double3 xformOp:translate = (91.27874306227827, -168.80960620832755, 81.99850250299916) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_13" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (96.41312, 31.279135, 76.980064) + float3 xformOp:scale = (0.98567414, 0.9856742, 0.98567426) + double3 xformOp:translate = (83.83837814952075, -189.24735545488528, 89.68797488309048) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_21" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (1.066759, -52.822353, 63.310623) + float3 xformOp:scale = (0.9856743, 0.9856744, 0.9856743) + double3 xformOp:translate = (90.66224152320507, -185.17929380454575, 88.99684440761104) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_39" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (177.24446, -1.1251347, 168.73134) + float3 xformOp:scale = (0.9999992, 0.9999994, 0.99999934) + double3 xformOp:translate = (82.94448561739883, -187.67984325670665, 81.99850424110839) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_40" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (25.420618, 46.272057, 8.252314) + float3 xformOp:scale = (0.98567325, 0.9856733, 0.98567337) + double3 xformOp:translate = (87.48692905126315, -188.09344044012056, 88.8124798239447) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_42" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (4.7125416, 4.2686863, -0.9857684) + float3 xformOp:scale = (1.0000005, 1.0000002, 1.0000004) + double3 xformOp:translate = (81.19606329598734, -182.92833023727513, 89.44440089457424) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_45" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (177.24443, -1.1251428, 168.73135) + float3 xformOp:scale = (0.99999964, 0.99999964, 0.9999996) + double3 xformOp:translate = (83.2541169001596, -169.2167550786468, 81.99849287763716) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_46" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (90.898, -15.097664, 61.912323) + float3 xformOp:scale = (0.9856735, 0.9856734, 0.9856734) + double3 xformOp:translate = (87.90831054724615, -185.7976434130161, 89.38703629446627) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_49" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (-1.7342469, -0.69065285, 81.736275) + float3 xformOp:scale = (0.9856737, 0.98567367, 0.98567367) + double3 xformOp:translate = (90.4795775963596, -170.99837228164898, 81.1519105930923) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_51" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (177.24443, -1.1251308, 168.73134) + float3 xformOp:scale = (0.99999934, 0.9999995, 0.9999994) + double3 xformOp:translate = (96.98696108244485, -170.47367107781432, 81.99850480523016) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_67" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (-68.09408, 53.006763, -62.96851) + float3 xformOp:scale = (0.98567325, 0.9856731, 0.9856732) + double3 xformOp:translate = (85.92863430704672, -189.67608694598476, 89.59319334110879) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_3" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (1.7099236, 1.3958248, 22.355247) + float3 xformOp:scale = (1.0066514, 1.0066514, 1.0066514) + double3 xformOp:translate = (113.86265527516449, -176.49064188942324, 80.23161043299135) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_4" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-13.603111, -24.261578, 26.615194) + float3 xformOp:scale = (1.0066508, 1.0066509, 1.0066509) + double3 xformOp:translate = (79.47016164614868, -180.82852319449304, 90.84047014320434) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_6" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (0.33469504, -0.99710053, 21.953455) + float3 xformOp:scale = (0.9999987, 0.9999987, 0.9999987) + double3 xformOp:translate = (117.05811637142762, -167.61441208734396, 80.33331029134541) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_7" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-7.2513676, -2.901598, 17.080624) + float3 xformOp:scale = (1.0066508, 1.0066507, 1.0066507) + double3 xformOp:translate = (92.53067776263092, -176.55448945314077, 89.50603045195982) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_8" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-101.13339, -55.48367, 90.10698) + float3 xformOp:scale = (1.0331545, 1.0331545, 1.0331545) + double3 xformOp:translate = (93.73328809852943, -178.40152347767167, 87.91306741536641) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_9" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-70.75669, 6.72467, 70.71984) + float3 xformOp:scale = (0.9999991, 0.99999905, 0.99999905) + double3 xformOp:translate = (85.60195029213504, -170.9569321565874, 90.30065255766459) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_10" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (4.555438, 2.2790463, 91.93785) + float3 xformOp:scale = (1.006652, 1.006652, 1.0066521) + double3 xformOp:translate = (122.39148353710004, -173.14884417119944, 81.14035809500646) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_11" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-97.387535, -21.293818, 82.638084) + float3 xformOp:scale = (0.9999988, 0.99999887, 0.99999887) + double3 xformOp:translate = (93.31402915745778, -170.89919186093144, 90.55930999087437) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_12" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-33.6833, -3.7828596, -18.664087) + float3 xformOp:scale = (0.999999, 0.9999991, 0.99999905) + double3 xformOp:translate = (93.33418074830138, -174.04316205012185, 89.8834778819346) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_13" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (179.74539, -0.53286654, 157.87576) + float3 xformOp:scale = (0.99999934, 0.9999994, 0.9999994) + double3 xformOp:translate = (124.16438772576427, -175.92896333041932, 81.09703337558535) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_15" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-79.60387, -56.285374, 64.474915) + float3 xformOp:scale = (1.0331542, 1.0331542, 1.0331544) + double3 xformOp:translate = (96.50853434417141, -186.33723365318502, 90.19559289068903) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_16" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (0.8080251, 1.7579421, 16.621204) + float3 xformOp:scale = (1.0066502, 1.0066501, 1.0066501) + double3 xformOp:translate = (122.00713296752562, -173.76290778691234, 80.40538738392405) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_17" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-13.126007, -15.46382, 60.30495) + float3 xformOp:scale = (1.0066509, 1.0066508, 1.0066509) + double3 xformOp:translate = (94.49803701259663, -175.54580634286916, 89.71240200281648) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_20" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-3.3360693, 28.115793, -2.0590224) + float3 xformOp:scale = (0.99999887, 0.99999887, 0.99999887) + double3 xformOp:translate = (91.98086232272365, -171.7724557603902, 89.76326045818846) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_21" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-52.21663, -9.351154, 1.6997589) + float3 xformOp:scale = (1.0066513, 1.0066513, 1.0066514) + double3 xformOp:translate = (78.87588102493426, -179.78001919998695, 89.46970262245173) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_23" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-36.07872, -48.07331, 14.195091) + float3 xformOp:scale = (1.0331557, 1.0331557, 1.0331557) + double3 xformOp:translate = (97.46882644059892, -186.06881514679404, 90.68098378829814) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_24" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-152.10995, -25.947193, 109.86589) + float3 xformOp:scale = (0.99999964, 0.9999996, 0.9999995) + double3 xformOp:translate = (80.76290548096134, -178.0178997130401, 89.78936949673681) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_25" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (0.13162437, 14.097052, 90.82334) + float3 xformOp:scale = (1.0066509, 1.0066508, 1.0066507) + double3 xformOp:translate = (92.90280129988483, -175.97763581288675, 90.2953415474662) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_26" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (164.66432, -42.71358, 172.91394) + float3 xformOp:scale = (0.99999905, 0.99999905, 0.9999991) + double3 xformOp:translate = (81.802022646052, -180.3427603993079, 89.86911507362437) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_27" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-22.935322, 29.913424, -31.832361) + float3 xformOp:scale = (1.0066503, 1.0066503, 1.0066504) + double3 xformOp:translate = (94.03692455281359, -174.25049068968212, 91.08908186872654) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_28" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-152.10995, -25.947193, 109.8659) + float3 xformOp:scale = (0.9999994, 0.9999995, 0.99999946) + double3 xformOp:translate = (80.76289090044656, -176.89516477922663, 88.82486965591313) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_29" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (13.95346, 87.23283, -176.29546) + float3 xformOp:scale = (0.9999986, 0.9999986, 0.9999985) + double3 xformOp:translate = (89.94854178852654, -170.96084951862082, 90.84954966703376) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_30" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-140.69666, -12.6834345, 128.89026) + float3 xformOp:scale = (1.0066504, 1.0066504, 1.0066504) + double3 xformOp:translate = (80.52587204878125, -175.43249438269964, 89.71220160685004) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_31" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-10.261756, -3.2115843, 93.89053) + float3 xformOp:scale = (1.0066504, 1.0066506, 1.0066506) + double3 xformOp:translate = (92.6608473549685, -176.60484683521034, 91.23717978761445) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_33" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-7.68396, -6.3556705, 35.825737) + float3 xformOp:scale = (1.0331557, 1.0331556, 1.0331557) + double3 xformOp:translate = (89.82691969669722, -183.02537652867488, 90.44636080080338) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_34" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-13.603069, -24.261591, 26.615248) + float3 xformOp:scale = (1.0066504, 1.0066506, 1.0066506) + double3 xformOp:translate = (108.99022864769663, -178.07724201816978, 82.36655677818524) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_35" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (17.344538, -75.28946, -30.027458) + float3 xformOp:scale = (0.99999905, 0.9999991, 0.99999905) + double3 xformOp:translate = (91.23804123894152, -179.0201709452472, 89.55956370046523) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_36" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-130.73573, 33.73724, -60.44604) + float3 xformOp:scale = (0.9999988, 0.99999887, 0.99999875) + double3 xformOp:translate = (90.18825214287324, -172.9725078044084, 90.53370554987983) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_37" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-0.3997203, 0.76873076, 0.4278627) + float3 xformOp:scale = (1.0066524, 1.0066524, 1.0066524) + double3 xformOp:translate = (124.86057549260441, -179.62398470994955, 80.34695777222872) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_38" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-53.708244, -52.532993, 71.92616) + float3 xformOp:scale = (1.0066497, 1.0066499, 1.0066497) + double3 xformOp:translate = (90.58660817245405, -176.42827843722264, 90.40269752905812) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_39" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (1.7099228, 1.3958242, 22.355312) + float3 xformOp:scale = (1.0066514, 1.0066514, 1.0066514) + double3 xformOp:translate = (106.56438732016986, -209.37618129370446, 80.2316134634071) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_40" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-10.261752, -3.211584, 93.89053) + float3 xformOp:scale = (1.0066504, 1.0066506, 1.0066506) + double3 xformOp:translate = (97.19299298504208, -183.8039727052516, 90.87925134215962) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_41" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-68.68768, -38.455685, 70.45745) + float3 xformOp:scale = (1.0331539, 1.0331538, 1.0331539) + double3 xformOp:translate = (94.95967155076849, -183.9551391128237, 89.95626665782993) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_43" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (164.66434, -42.713585, 172.91394) + float3 xformOp:scale = (0.99999917, 0.9999991, 0.99999917) + double3 xformOp:translate = (91.33573137979883, -175.1430673605381, 91.5821877633056) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_44" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-74.895485, 2.9364405, 124.70044) + float3 xformOp:scale = (0.999999, 0.99999905, 0.9999991) + double3 xformOp:translate = (87.55231497301145, -173.4598241856244, 90.70120525891781) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_45" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (0.13162547, 14.0970545, 90.82335) + float3 xformOp:scale = (1.0066509, 1.0066509, 1.0066509) + double3 xformOp:translate = (97.43493371221484, -183.1767762160825, 89.93744854586535) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_46" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (160.88467, -33.882156, 136.09369) + float3 xformOp:scale = (1.0066501, 1.00665, 1.0066501) + double3 xformOp:translate = (86.38261840461132, -176.62873807286553, 90.82841839083122) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_48" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (0.6661682, 178.53972, 80.492714) + float3 xformOp:scale = (1.006651, 1.006651, 1.006651) + double3 xformOp:translate = (118.36460988017737, -170.90404913617368, 81.09845662872033) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_50" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (9.579858, -58.551678, -19.822834) + float3 xformOp:scale = (1.0331552, 1.0331553, 1.0331553) + double3 xformOp:translate = (95.94976763424972, -184.43085659259083, 90.1002692625098) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_51" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-1.413907, 1.2390829, 24.112217) + float3 xformOp:scale = (1.0066504, 1.0066504, 1.0066506) + double3 xformOp:translate = (115.20365977294117, -171.69962287899972, 80.31987654464233) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_52" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-1.4139134, 1.2390879, 24.112186) + float3 xformOp:scale = (1.0066501, 1.0066501, 1.00665) + double3 xformOp:translate = (84.52567558101103, -138.9192117362283, 80.31987781030134) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_53" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (17.34454, -75.289444, -30.02747) + float3 xformOp:scale = (0.99999905, 0.9999991, 0.99999905) + double3 xformOp:translate = (91.88483541762028, -174.4330678925421, 90.42212205777382) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_55" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (0.66615295, 178.53972, 80.4927) + float3 xformOp:scale = (1.0066507, 1.0066508, 1.0066508) + double3 xformOp:translate = (87.68657248000551, -138.12358719755122, 81.09844717460255) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_56" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-22.3702, -19.745813, 33.90012) + float3 xformOp:scale = (1.0066508, 1.0066509, 1.0066509) + double3 xformOp:translate = (112.67860658498756, -176.31632890225967, 80.7589263752183) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_57" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (9.579856, -58.551678, -19.82282) + float3 xformOp:scale = (1.0331553, 1.0331553, 1.0331553) + double3 xformOp:translate = (95.33110714023526, -186.24396818660426, 90.240426997445) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_58" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-114.09421, -66.703575, 83.27238) + float3 xformOp:scale = (1.0331558, 1.0331558, 1.0331559) + double3 xformOp:translate = (94.13689996718782, -186.1386390523772, 90.52957399989751) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_59" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-0.97344637, 0.924427, 110.91278) + float3 xformOp:scale = (0.9999987, 0.9999986, 0.99999875) + double3 xformOp:translate = (116.15345813951768, -175.48864022665856, 80.3334643956299) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_60" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (43.662388, -22.134218, -12.013349) + float3 xformOp:scale = (1.0066518, 1.0066516, 1.0066518) + double3 xformOp:translate = (95.52632967175973, -175.71030463045892, 91.44817891256646) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_61" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-93.35359, 25.219877, 68.5658) + float3 xformOp:scale = (0.9999996, 0.9999995, 0.9999995) + double3 xformOp:translate = (81.27481869145315, -179.14522942887703, 90.1560258615772) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_65" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (177.26231, 4.3663363, 133.5876) + float3 xformOp:scale = (1.0066506, 1.0066504, 1.0066504) + double3 xformOp:translate = (83.67675046700364, -176.94380126666738, 90.20472711895573) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_66" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (9.572213, -47.5173, -28.261972) + float3 xformOp:scale = (0.99999934, 0.9999994, 0.9999993) + double3 xformOp:translate = (86.53960461979878, -171.89048654255924, 90.47819580825966) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_67" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-34.00122, -35.202843, 30.015663) + float3 xformOp:scale = (1.0066508, 1.0066507, 1.0066508) + double3 xformOp:translate = (86.90700501101725, -174.74982929521747, 91.2505045397661) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_68" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-11.086513, -4.5810137, 65.102005) + float3 xformOp:scale = (1.00665, 1.00665, 1.00665) + double3 xformOp:translate = (85.83540314072627, -175.18381536614064, 89.55414441710357) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_69" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (0.3346909, -0.99712193, 21.953438) + float3 xformOp:scale = (0.9999987, 0.99999887, 0.9999988) + double3 xformOp:translate = (86.38014117723742, -134.833928277936, 80.3333017234925) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_70" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-50.32997, -58.612553, 3.8923836) + float3 xformOp:scale = (0.99999857, 0.9999986, 0.9999985) + double3 xformOp:translate = (93.12605964701423, -173.3852813190657, 89.20931362487886) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_72" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-13.603109, -24.26158, 26.615192) + float3 xformOp:scale = (1.0066512, 1.0066512, 1.0066512) + double3 xformOp:translate = (83.5971776638759, -176.2820058620672, 90.04496416117544) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_73" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (2.9613872, -37.63073, 8.939056) + float3 xformOp:scale = (0.9999986, 0.99999857, 0.99999857) + double3 xformOp:translate = (89.01522031252594, -174.25525720805422, 89.95655674095217) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_74" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-7.413072, -22.857468, -156.44089) + float3 xformOp:scale = (0.9999995, 0.9999995, 0.99999946) + double3 xformOp:translate = (82.82397707103257, -170.38877840396225, 90.61846746107992) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_76" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (15.332635, -72.5105, 1.4455035) + float3 xformOp:scale = (1.0066508, 1.0066507, 1.0066508) + double3 xformOp:translate = (92.42875160425021, -186.7902742701834, 88.75227378931129) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_78" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-35.307213, -40.370983, 27.677462) + float3 xformOp:scale = (0.99999845, 0.9999985, 0.99999857) + double3 xformOp:translate = (87.78346070308112, -170.4708302149512, 90.01059856281671) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_79" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-76.95607, -48.66149, 75.12289) + float3 xformOp:scale = (1.0331552, 1.0331552, 1.0331553) + double3 xformOp:translate = (93.35870933255406, -184.3635738366283, 88.61453662067652) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_81" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-133.12296, 9.093651, 132.3407) + float3 xformOp:scale = (1.0066512, 1.0066512, 1.0066512) + double3 xformOp:translate = (81.89256653842011, -176.0398078090693, 89.93262308981872) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_82" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-53.70823, -52.533016, 71.92611) + float3 xformOp:scale = (1.0066495, 1.0066496, 1.0066495) + double3 xformOp:translate = (95.11872516679566, -183.62744860747833, 90.0448296735604) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_83" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (173.80597, 14.72126, 79.01579) + float3 xformOp:scale = (1.0066514, 1.0066512, 1.0066513) + double3 xformOp:translate = (83.96109939470563, -174.51834470229323, 90.68800788784978) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_84" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-1.0426406, 5.0394864, 18.167389) + float3 xformOp:scale = (1.0066512, 1.0066509, 1.006651) + double3 xformOp:translate = (92.56154385228967, -181.62092598104562, 87.46522050649482) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_85" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-125.97495, -7.6461296, 115.78442) + float3 xformOp:scale = (1.0066512, 1.0066513, 1.0066513) + double3 xformOp:translate = (79.0275521590622, -173.71065633880562, 91.25150566510311) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_87" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-115.32563, 47.663757, 129.20958) + float3 xformOp:scale = (0.9999988, 0.9999988, 0.9999988) + double3 xformOp:translate = (81.301984164039, -171.58132660977196, 89.9905137237475) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_89" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-140.69666, -12.683441, 128.89026) + float3 xformOp:scale = (1.0066506, 1.0066504, 1.0066504) + double3 xformOp:translate = (80.52586937856347, -173.00623748612472, 90.26804917053694) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_90" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-8.757398, -1.2439107, 6.064455) + float3 xformOp:scale = (1.0066504, 1.0066506, 1.0066506) + double3 xformOp:translate = (90.79768522749885, -181.38797422633198, 87.50690644264643) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_94" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-143.06589, 16.478128, 173.5582) + float3 xformOp:scale = (1.0066507, 1.0066506, 1.0066504) + double3 xformOp:translate = (81.76885715776541, -174.87393917153807, 90.62193339446712) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_97" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-113.703255, 7.747769, 117.547165) + float3 xformOp:scale = (0.9999996, 0.9999995, 0.9999996) + double3 xformOp:translate = (84.84346017308758, -171.62755812565382, 90.54841123104165) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_98" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-0.9734575, 0.92443645, 110.91282) + float3 xformOp:scale = (0.99999887, 0.9999989, 0.9999987) + double3 xformOp:translate = (108.85514319173035, -158.3309304322155, 80.33346160101661) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_99" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (164.66434, -42.71358, 172.91393) + float3 xformOp:scale = (0.999999, 0.99999905, 0.999999) + double3 xformOp:translate = (94.5728409563273, -179.9569869501537, 89.60221895303177) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_101" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-68.687645, -38.45567, 70.4574) + float3 xformOp:scale = (1.0331539, 1.0331539, 1.0331539) + double3 xformOp:translate = (93.58109000419992, -183.38294993977837, 89.87745746396735) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_102" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-53.708218, -52.533012, 71.92611) + float3 xformOp:scale = (1.0066495, 1.0066496, 1.0066495) + double3 xformOp:translate = (93.8236676899711, -181.24218135013942, 88.42275362092454) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_103" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-152.10995, -25.947197, 109.86589) + float3 xformOp:scale = (0.9999998, 0.99999964, 0.9999997) + double3 xformOp:translate = (89.64975032504202, -178.67822185204005, 90.63978237978547) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_105" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-101.1329, -19.410807, 101.56051) + float3 xformOp:scale = (0.99999905, 0.99999905, 0.99999905) + double3 xformOp:translate = (86.7794155989007, -169.5479432563904, 91.03608904415398) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_107" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-13.603104, -24.26158, 26.615196) + float3 xformOp:scale = (1.0066512, 1.0066512, 1.0066512) + double3 xformOp:translate = (85.84910059990449, -174.45100351307417, 91.17239492867597) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_108" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-171.82909, 5.2870946, 142.36617) + float3 xformOp:scale = (1.0066501, 1.00665, 1.0066501) + double3 xformOp:translate = (88.04360543419779, -181.2019320392256, 90.17319129815888) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_110" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-113.70327, 7.7477727, 117.547165) + float3 xformOp:scale = (0.99999964, 0.9999996, 0.9999996) + double3 xformOp:translate = (82.56201635210505, -170.71510045295418, 90.54841715427315) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_111" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-52.21663, -9.351142, 1.6997474) + float3 xformOp:scale = (1.0066515, 1.0066514, 1.0066515) + double3 xformOp:translate = (87.76275183530029, -180.44035012525438, 90.32018369600974) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_113" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (10.449825, 52.847095, 88.19584) + float3 xformOp:scale = (0.9999992, 0.9999992, 0.9999993) + double3 xformOp:translate = (82.77114472932729, -172.8426272823842, 90.10643257329079) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_115" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (173.80598, 14.721257, 79.01579) + float3 xformOp:scale = (1.0066515, 1.0066514, 1.0066514) + double3 xformOp:translate = (81.6796662004962, -173.60596323103215, 90.68799868465364) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_116" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (89.034386, -51.036026, -50.200577) + float3 xformOp:scale = (1.0066506, 1.0066504, 1.0066506) + double3 xformOp:translate = (85.78240257936646, -181.5117761554661, 90.92219110641828) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_117" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-1.0426438, 5.039475, 18.167404) + float3 xformOp:scale = (1.0066512, 1.0066512, 1.006651) + double3 xformOp:translate = (92.17890207269531, -176.1138442774407, 87.46523222316574) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_119" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (160.88469, -33.882145, 136.09369) + float3 xformOp:scale = (1.0066501, 1.0066501, 1.0066501) + double3 xformOp:translate = (85.73575984490353, -181.2157927287159, 89.96581317390645) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_121" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-101.1329, -19.410807, 101.56051) + float3 xformOp:scale = (0.999999, 0.9999991, 0.9999991) + double3 xformOp:translate = (84.52748839511935, -171.37898268510133, 89.90867688013032) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_122" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-74.895485, 2.936443, 124.70044) + float3 xformOp:scale = (0.99999917, 0.9999993, 0.9999992) + double3 xformOp:translate = (86.90542885084122, -178.04693320861875, 89.83866105463608) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_125" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-8.757394, -1.2439084, 6.0644507) + float3 xformOp:scale = (1.0066504, 1.0066506, 1.0066506) + double3 xformOp:translate = (86.9137800287474, -181.16121272891974, 88.62431218573289) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_126" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-68.79763, -47.28402, 71.27215) + float3 xformOp:scale = (1.033154, 1.0331539, 1.0331541) + double3 xformOp:translate = (92.80742324392713, -178.06507582174945, 88.47729505841733) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_127" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (9.572217, -47.517296, -28.261961) + float3 xformOp:scale = (0.9999995, 0.9999995, 0.99999946) + double3 xformOp:translate = (84.28766696114963, -173.7215454139172, 89.35074925023652) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_128" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-125.974945, -7.646117, 40.67274) + float3 xformOp:scale = (1.0066509, 1.0066508, 1.0066509) + double3 xformOp:translate = (79.03857886344325, -175.24326897151775, 89.9258901195989) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_130" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-35.3072, -40.370975, 27.677452) + float3 xformOp:scale = (0.9999984, 0.9999984, 0.99999833) + double3 xformOp:translate = (85.53152776698609, -172.30187861340417, 88.88315468540304) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_133" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-68.68765, -38.45567, 70.45738) + float3 xformOp:scale = (1.033154, 1.033154, 1.0331539) + double3 xformOp:translate = (93.19840432685861, -177.87596413469146, 89.87745432684133) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_134" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (164.66432, -42.71358, 172.91393) + float3 xformOp:scale = (0.9999991, 0.99999905, 0.999999) + double3 xformOp:translate = (90.68889129528333, -179.73015246216835, 90.71954762051072) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_137" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (173.80598, 14.721265, 79.01579) + float3 xformOp:scale = (1.0066515, 1.0066515, 1.0066515) + double3 xformOp:translate = (83.31428719541739, -179.1055001084832, 89.82545374831433) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_138" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-53.70823, -52.533016, 71.92611) + float3 xformOp:scale = (1.0066495, 1.0066496, 1.0066496) + double3 xformOp:translate = (89.93976169343611, -181.0153628413391, 89.54014558813554) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_139" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-52.216633, -9.3511505, 1.6997577) + float3 xformOp:scale = (1.0066514, 1.0066516, 1.0066515) + double3 xformOp:translate = (88.40958649737732, -175.8532880659846, 91.18274792150771) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_140" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-8.143833, 26.02171, 94.32339) + float3 xformOp:scale = (1.0066506, 1.0066506, 1.0066504) + double3 xformOp:translate = (92.01401011089911, -181.38408948770774, 90.35901981053583) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_141" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (1.7099177, 1.3958265, 22.355305) + float3 xformOp:scale = (1.0066513, 1.0066513, 1.0066513) + double3 xformOp:translate = (106.56438590043874, -159.3328941775993, 80.2316138315162) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_142" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-10.261755, -3.2115986, 93.89053) + float3 xformOp:scale = (1.0066506, 1.0066506, 1.0066506) + double3 xformOp:translate = (95.51526854683709, -175.91167132044603, 89.25719544813957) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_143" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (2.9613914, -37.630726, 8.939067) + float3 xformOp:scale = (0.99999857, 0.99999845, 0.9999985) + double3 xformOp:translate = (88.36835388767591, -178.84243580284206, 89.0939717051459) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_144" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-13.60311, -24.26158, 26.615192) + float3 xformOp:scale = (1.006651, 1.006651, 1.006651) + double3 xformOp:translate = (85.2022516022812, -179.038070862421, 90.30982356994606) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_145" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (10.44983, 52.847103, 88.19584) + float3 xformOp:scale = (0.99999917, 0.9999991, 0.99999917) + double3 xformOp:translate = (84.4057341398186, -178.34223593395606, 89.24388975037363) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_147" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-0.9734638, 0.9244229, 110.91283) + float3 xformOp:scale = (0.9999986, 0.99999875, 0.99999875) + double3 xformOp:translate = (108.85516465220357, -208.3742256301507, 80.33346226538497) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_149" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-171.82909, 5.287084, 142.36617) + float3 xformOp:scale = (1.0066502, 1.0066502, 1.0066502) + double3 xformOp:translate = (88.6904546346679, -176.6148382237311, 91.03577674681517) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_150" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (177.26231, 4.366346, 133.5876) + float3 xformOp:scale = (1.0066502, 1.0066503, 1.0066503) + double3 xformOp:translate = (83.02992256771259, -181.5309342978884, 89.34216084979295) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_151" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-11.086502, -4.581005, 65.102) + float3 xformOp:scale = (1.0066497, 1.00665, 1.0066499) + double3 xformOp:translate = (79.456510098443, -181.56136892958824, 89.22221712868759) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_152" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-10.261755, -3.2115853, 93.89053) + float3 xformOp:scale = (1.0066506, 1.0066507, 1.0066506) + double3 xformOp:translate = (92.62206518352357, -183.0597915651657, 90.11766532228242) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_153" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (10.436474, -49.328156, 2.601901) + float3 xformOp:scale = (0.9999998, 0.9999998, 0.9999998) + double3 xformOp:translate = (90.24447442750412, -173.90145561687575, 90.15082711696606) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_154" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-34.001232, -35.20284, 30.015656) + float3 xformOp:scale = (1.0066507, 1.0066507, 1.0066506) + double3 xformOp:translate = (86.2601850766498, -179.33700681230155, 90.38797237158349) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_156" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (43.66239, -22.134218, -12.013351) + float3 xformOp:scale = (1.0066515, 1.0066515, 1.0066514) + double3 xformOp:translate = (95.4874758355659, -182.16530303500073, 90.32864888095261) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_158" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-152.10992, -25.947216, 109.86585) + float3 xformOp:scale = (0.9999993, 0.9999992, 0.99999934) + double3 xformOp:translate = (93.20231205157654, -184.6857596983177, 90.11656049411762) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_159" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-11.99142, -26.593163, 94.344795) + float3 xformOp:scale = (1.0066506, 1.0066506, 1.0066504) + double3 xformOp:translate = (96.21349364287039, -180.16043572503241, 91.31690175149214) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_160" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (164.66432, -42.713585, 172.91394) + float3 xformOp:scale = (0.9999992, 0.9999991, 0.99999917) + double3 xformOp:translate = (94.88836744451709, -178.83133688305554, 91.58218510754719) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_161" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-33.68328, -3.7828481, -18.664085) + float3 xformOp:scale = (0.99999934, 0.99999946, 0.99999946) + double3 xformOp:translate = (96.88682193015416, -177.73145381842764, 89.8834590929639) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_162" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-22.935324, 29.913435, -31.832361) + float3 xformOp:scale = (1.0066503, 1.0066504, 1.0066503) + double3 xformOp:translate = (97.5895164199946, -177.938737718122, 91.08908116153347) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_163" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-8.757397, -1.2438896, 6.0644417) + float3 xformOp:scale = (1.0066504, 1.0066506, 1.0066507) + double3 xformOp:translate = (87.56060996013571, -176.57408582034986, 89.48687706821514) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_164" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (43.66238, -22.13421, -12.013352) + float3 xformOp:scale = (1.0066518, 1.0066516, 1.0066518) + double3 xformOp:translate = (99.07892097855438, -179.39857291956838, 91.44817355107007) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_165" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-13.126014, -15.463821, 60.304947) + float3 xformOp:scale = (1.0066507, 1.0066507, 1.0066507) + double3 xformOp:translate = (98.05064258088649, -179.2341410220298, 89.71240932733758) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_166" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-152.10995, -25.947195, 109.86589) + float3 xformOp:scale = (0.9999997, 0.9999997, 0.99999976) + double3 xformOp:translate = (90.2965742746035, -174.09114458396078, 91.50238589182112) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_168" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-171.26097, 35.737976, 78.10025) + float3 xformOp:scale = (0.9999992, 0.99999917, 0.9999991) + double3 xformOp:translate = (88.48540147697247, -171.8057134493502, 90.41569133506965) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_169" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (0.13161664, 14.097059, 90.82335) + float3 xformOp:scale = (1.006651, 1.0066509, 1.0066509) + double3 xformOp:translate = (96.45542995516718, -179.66586882561836, 90.29534147904512) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_170" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-7.413074, -22.857466, -156.4409) + float3 xformOp:scale = (0.9999995, 0.99999964, 0.9999996) + double3 xformOp:translate = (78.53548640358434, -176.76643865879095, 89.93660855349111) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_171" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (-113.70327, 7.74778, 117.54717) + float3 xformOp:scale = (0.9999995, 0.9999996, 0.9999996) + double3 xformOp:translate = (78.46453116791366, -178.00508184979765, 90.21648468146313) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_172" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (10.449825, 52.847088, 88.19584) + float3 xformOp:scale = (0.9999992, 0.9999992, 0.99999934) + double3 xformOp:translate = (78.67368817408362, -180.13262976123593, 89.77453139503588) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_173" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (9.572222, -47.5173, -28.261957) + float3 xformOp:scale = (0.9999996, 0.9999995, 0.99999946) + double3 xformOp:translate = (80.16068704832242, -178.2680435588138, 90.14628148994872) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioA_174" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioA" + } + ) + { + float3 xformOp:rotateXYZ = (173.80598, 14.721252, 79.01579) + float3 xformOp:scale = (1.0066513, 1.0066513, 1.0066514) + double3 xformOp:translate = (77.58219508778967, -180.89589491730194, 90.3560902306007) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_1" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (0.98698723, 24.463081, -175.4051) + float3 xformOp:scale = (0.9856739, 0.98567396, 0.9856739) + double3 xformOp:translate = (89.86247159735592, -190.40961478093524, 90.54908533296341) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_2" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (108.98045, -38.565506, 127.575096) + float3 xformOp:scale = (0.9856747, 0.98567474, 0.9856748) + double3 xformOp:translate = (91.51529180447932, -189.4276947814572, 90.04805498575924) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_3" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (-178.4727, -15.713543, 81.54056) + float3 xformOp:scale = (0.9999997, 0.99999964, 0.9999996) + double3 xformOp:translate = (89.36146490760453, -186.1053967591231, 90.76087258049265) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_4" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (68.84124, 3.1091712, 60.05171) + float3 xformOp:scale = (0.98567367, 0.9856737, 0.9856737) + double3 xformOp:translate = (87.20930569176218, -189.37168944066138, 90.28962139483858) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_6" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (-178.4727, -15.713559, 81.540565) + float3 xformOp:scale = (0.9999997, 0.9999998, 0.99999976) + double3 xformOp:translate = (91.49439488251, -187.32531526046935, 90.76087693810456) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_7" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (-179.99458, -4.916629, 135.81053) + float3 xformOp:scale = (0.9999993, 0.9999994, 0.99999934) + double3 xformOp:translate = (89.92601248696076, -183.73661821978538, 90.26817106404933) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_8" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (100.37322, 29.23531, 96.59563) + float3 xformOp:scale = (0.9856737, 0.98567367, 0.9856737) + double3 xformOp:translate = (88.29223958739999, -189.12306729725412, 89.8963833065803) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_10" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (68.4161, -79.91867, 91.12383) + float3 xformOp:scale = (0.9856738, 0.9856737, 0.98567367) + double3 xformOp:translate = (82.86877296571336, -188.82385498595184, 90.90678393624769) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_12" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (25.420582, 46.27208, 8.252291) + float3 xformOp:scale = (0.9856733, 0.9856733, 0.98567325) + double3 xformOp:translate = (85.0029331236762, -189.59469569849455, 89.93992764921501) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_14" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (6.525919, -26.381018, -21.333319) + float3 xformOp:scale = (0.985674, 0.98567414, 0.98567414) + double3 xformOp:translate = (81.0940760742921, -187.76813177533452, 89.7469633397447) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_15" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (111.43766, 1.3102398, 114.27503) + float3 xformOp:scale = (0.98567444, 0.98567444, 0.98567444) + double3 xformOp:translate = (90.13700142318594, -190.07100175023442, 90.57494874023192) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_16" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (-12.762748, 37.088593, -11.848743) + float3 xformOp:scale = (0.9856737, 0.9856736, 0.9856736) + double3 xformOp:translate = (84.31650962844267, -185.7121850710741, 89.88037807741898) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_17" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (-22.175068, 45.550476, -50.797295) + float3 xformOp:scale = (0.98567337, 0.98567325, 0.98567325) + double3 xformOp:translate = (88.90497632194666, -186.90246875457748, 89.27343879019244) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_18" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (1.0668935, -52.822353, 63.310604) + float3 xformOp:scale = (0.98567367, 0.9856736, 0.98567367) + double3 xformOp:translate = (90.31122159169195, -187.90034582818214, 90.12428838758635) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_19" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (6.976112, 26.385447, 7.639095) + float3 xformOp:scale = (0.9999992, 0.9999992, 0.99999917) + double3 xformOp:translate = (89.97536609444026, -184.42923992244815, 89.96637381218872) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_20" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (111.43769, 1.3101776, 114.27502) + float3 xformOp:scale = (0.9856743, 0.9856744, 0.9856744) + double3 xformOp:translate = (90.48803032931636, -187.3499071943025, 89.4475219711652) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_22" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (125.350746, 15.736494, 114.11866) + float3 xformOp:scale = (0.9999996, 0.9999995, 0.9999996) + double3 xformOp:translate = (94.04880382860757, -187.58226365842353, 91.27600241600652) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_23" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (-1.7342374, -0.6906582, 81.736305) + float3 xformOp:scale = (0.98567384, 0.9856738, 0.9856739) + double3 xformOp:translate = (83.25887930433188, -161.6679423315382, 81.15190983075924) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_24" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (178.35379, 38.721645, -124.20052) + float3 xformOp:scale = (0.99999803, 0.99999803, 0.999998) + double3 xformOp:translate = (82.25418238710583, -178.01135477976305, 88.92623545033291) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_25" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (125.35071, 15.736467, 48.31084) + float3 xformOp:scale = (0.9999995, 0.9999996, 0.99999946) + double3 xformOp:translate = (95.32208047153242, -187.62986146422966, 91.27598454134153) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_26" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (177.24443, -1.1251518, 168.73138) + float3 xformOp:scale = (0.999999, 0.99999887, 0.9999989) + double3 xformOp:translate = (101.86237244132668, -193.83605156937153, 81.9985192013469) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_27" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (-156.93555, 29.924662, 139.17334) + float3 xformOp:scale = (0.9999979, 0.99999803, 0.999998) + double3 xformOp:translate = (87.19804127002934, -183.64528342673918, 90.83926542188979) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_28" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (2.658638, 0.5819624, 22.098333) + float3 xformOp:scale = (0.99999803, 0.999998, 0.999998) + double3 xformOp:translate = (97.51675879027798, -188.00625716389263, 81.22890592379896) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_29" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (-42.52863, 67.73439, -33.33567) + float3 xformOp:scale = (0.9999999, 0.99999976, 0.9999998) + double3 xformOp:translate = (82.4075907785492, -183.3708363108641, 89.53703211532886) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_30" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (100.373245, 29.23529, 96.59558) + float3 xformOp:scale = (0.9856733, 0.98567337, 0.9856733) + double3 xformOp:translate = (85.80825276874273, -190.6243129094653, 91.02381935880399) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_31" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (-1.7342606, -0.6906823, 81.73633) + float3 xformOp:scale = (0.98567295, 0.98567295, 0.985673) + double3 xformOp:translate = (98.62615205971838, -190.28440254622, 81.15191515066628) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_32" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (-0.92590976, -0.09246001, -175.81831) + float3 xformOp:scale = (0.9856728, 0.98567283, 0.9856728) + double3 xformOp:translate = (99.80601428957482, -195.1674810334463, 81.17799942053004) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_33" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (130.55272, -1.7134705, 131.40926) + double3 xformOp:translate = (91.53276656323803, -184.90595988674195, 89.98132991927133) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + } + + def "CheerioB_34" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (-178.7746, -3.6046662, 168.58318) + float3 xformOp:scale = (0.9999996, 0.9999994, 0.9999995) + double3 xformOp:translate = (92.06897749813376, -153.0953351503617, 81.21285581089046) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_35" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (-0.82897395, 1.2337081, -175.8173) + float3 xformOp:scale = (0.98567367, 0.98567367, 0.9856736) + double3 xformOp:translate = (89.69235843939265, -157.8877156960194, 81.1606462743853) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_36" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (-15.911795, 27.39232, 64.77553) + float3 xformOp:scale = (0.9856731, 0.98567325, 0.9856732) + double3 xformOp:translate = (88.14274198318711, -156.66667189702068, 80.80534837165857) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_37" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (-0.5054408, -0.65604216, 23.026457) + float3 xformOp:scale = (0.9999985, 0.9999986, 0.9999985) + double3 xformOp:translate = (83.95200085635193, -150.52520862823067, 80.28798827396993) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_38" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (6.4878993, 2.8996174, -11.945532) + float3 xformOp:scale = (0.9999994, 0.99999934, 0.9999994) + double3 xformOp:translate = (86.12457703223953, -183.60799052640485, 89.42721444086061) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_41" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (-22.175077, 45.55048, -50.797264) + float3 xformOp:scale = (0.98567295, 0.98567295, 0.9856729) + double3 xformOp:translate = (86.42100534910023, -188.40368648469465, 90.40084819551815) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_44" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (177.24443, -1.1251348, 168.73134) + float3 xformOp:scale = (0.9999978, 0.99999785, 0.9999978) + double3 xformOp:translate = (76.90462335787943, -188.83337931382928, 82.02369678630836) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_47" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (177.24449, -1.1251272, 168.73137) + float3 xformOp:scale = (0.99999887, 0.9999988, 0.99999887) + double3 xformOp:translate = (80.47732749408621, -159.87761673093044, 81.9984972204147) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_48" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (177.24445, -1.1251267, 117.60289) + float3 xformOp:scale = (0.9999995, 0.99999964, 0.9999995) + double3 xformOp:translate = (86.91756704553575, -161.25248614831233, 81.99849718269196) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_50" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (139.2229, -10.326733, 173.92352) + float3 xformOp:scale = (0.99999976, 0.9999997, 0.99999964) + double3 xformOp:translate = (91.50621619456484, -186.12329651474732, 90.68418795547683) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_52" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (-0.92594916, -0.092443, -175.81825) + float3 xformOp:scale = (0.9856731, 0.9856732, 0.9856732) + double3 xformOp:translate = (77.56769642841122, -162.20825192403134, 81.17799982907708) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_53" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (-1.7342317, -0.69074607, 81.73631) + float3 xformOp:scale = (0.9856738, 0.98567367, 0.9856737) + double3 xformOp:translate = (89.71709583751976, -124.18464309992106, 80.2921196182308) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_54" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (177.24448, -1.1250471, 117.60294) + float3 xformOp:scale = (1.0000004, 1.0000004, 1.0000004) + double3 xformOp:translate = (93.37573950183139, -123.76924566895005, 81.13869966611878) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_55" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (91.18652, -66.17944, 142.58698) + float3 xformOp:scale = (0.9856736, 0.98567367, 0.9856737) + double3 xformOp:translate = (79.0151926447663, -186.52037869267423, 89.15257151158728) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_56" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (-23.647722, 47.15531, -20.352457) + float3 xformOp:scale = (0.98567426, 0.9856742, 0.98567414) + double3 xformOp:translate = (83.03392205162557, -185.8991512234803, 90.07353184482565) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_57" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (-48.754864, 70.29441, -68.69058) + float3 xformOp:scale = (0.98567325, 0.9856732, 0.98567325) + double3 xformOp:translate = (81.44797262793935, -185.12854492079975, 90.35236851374259) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_58" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (41.810574, 60.303333, 52.00564) + float3 xformOp:scale = (0.9999989, 0.9999989, 0.999999) + double3 xformOp:translate = (83.00756963953364, -183.3087037935997, 90.33015736487735) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_59" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (25.832846, -25.424208, -50.11314) + float3 xformOp:scale = (0.99999917, 0.99999905, 0.9999991) + double3 xformOp:translate = (79.40318615629968, -185.05320112579173, 90.75165300024591) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_60" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (0.4907258, -13.758553, 72.38147) + float3 xformOp:scale = (0.9999996, 0.9999997, 0.99999964) + double3 xformOp:translate = (80.6995487383065, -183.38819342922278, 90.25393961276019) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_61" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (30.700504, 9.933028, -34.82739) + float3 xformOp:scale = (0.9856731, 0.9856732, 0.9856732) + double3 xformOp:translate = (80.05573641883109, -185.32136413252454, 89.83678898771899) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_62" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (35.09604, 66.19488, -18.956167) + float3 xformOp:scale = (0.9856722, 0.9856721, 0.9856721) + double3 xformOp:translate = (80.11325572787574, -185.96262842717482, 89.14100340993295) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_63" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (6.9761176, 26.385443, 7.6391087) + float3 xformOp:scale = (0.99999976, 0.9999998, 0.9999997) + double3 xformOp:translate = (87.49136948457789, -185.93044026505748, 91.09377991235411) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_64" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (1.0668048, -52.822353, 63.31067) + float3 xformOp:scale = (0.9856737, 0.98567367, 0.9856737) + double3 xformOp:translate = (88.17830023251514, -186.68053904807977, 90.12428286558568) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_65" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (124.744705, -26.214176, -60.454163) + float3 xformOp:scale = (0.9856735, 0.9856734, 0.98567337) + double3 xformOp:translate = (83.00859835996943, -186.83147761886252, 90.59310611804551) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_66" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (111.43771, 1.3102285, 114.275055) + float3 xformOp:scale = (0.9856744, 0.9856744, 0.9856744) + double3 xformOp:translate = (88.0040441101091, -188.85118671018404, 90.57493993337246) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_68" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (-158.57779, 38.676205, 177.31502) + float3 xformOp:scale = (0.98567307, 0.9856731, 0.98567325) + double3 xformOp:translate = (82.05332963268009, -184.47607738716664, 91.57770872435266) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_69" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (68.84125, 3.1091633, 60.051773) + float3 xformOp:scale = (0.98567337, 0.9856735, 0.9856734) + double3 xformOp:translate = (89.69332318953803, -187.87047608258914, 89.16214955110001) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_70" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (72.8222, 7.063329, 114.73445) + float3 xformOp:scale = (0.98567355, 0.9856735, 0.98567355) + double3 xformOp:translate = (85.56822987069927, -186.6665176724361, 90.68953734427572) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_71" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (141.08075, 18.871344, 129.31749) + float3 xformOp:scale = (1.0000004, 1.0000004, 1.0000002) + double3 xformOp:translate = (92.4642029269005, -188.0797884293568, 90.29746646818597) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_72" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (7.628135, 5.0990987, 75.90166) + float3 xformOp:scale = (0.99999857, 0.9999985, 0.99999857) + double3 xformOp:translate = (81.01032115788507, -182.81503782788403, 91.17562649277193) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_73" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float xformOp:rotateY = -4.6403127 + double3 xformOp:translate = (84.41499708832629, -183.12642669677734, 89.39228088722317) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateY"] + } + + def "CheerioB_74" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (155.12961, 29.70489, 112.624115) + float3 xformOp:scale = (0.98567307, 0.98567307, 0.985673) + double3 xformOp:translate = (82.96855502706055, -185.62713113660365, 91.5155798702159) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_75" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (169.11166, -3.9016745, 144.50848) + float3 xformOp:scale = (0.9999987, 0.9999988, 0.99999875) + double3 xformOp:translate = (84.90074916812407, -183.38165859746795, 91.09931526290278) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_76" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (8.258537, 17.656729, 41.97365) + float3 xformOp:scale = (0.9999989, 0.9999989, 0.999999) + double3 xformOp:translate = (79.06761223855693, -183.62631499660256, 89.63995040985336) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_77" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (162.17822, -34.232574, 82.451065) + float3 xformOp:scale = (0.98567426, 0.9856742, 0.98567426) + double3 xformOp:translate = (84.48283974412846, -188.18611616696847, 90.4907001681265) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_78" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (48.826195, 17.401512, -12.664117) + float3 xformOp:scale = (0.9999994, 0.99999946, 0.9999995) + double3 xformOp:translate = (85.18270095146292, -184.17053668400922, 91.13572048262102) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_79" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (25.323664, 40.519207, 11.047433) + float3 xformOp:scale = (1.0000005, 1.0000006, 1.0000005) + double3 xformOp:translate = (86.46625165321191, -185.47244888491431, 91.17324475764616) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_80" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (178.35379, 38.721638, -124.20049) + float3 xformOp:scale = (0.99999934, 0.9999994, 0.9999994) + double3 xformOp:translate = (82.25417307713084, -179.1340849162682, 89.89068013072905) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "CheerioB_81" ( + add references = @./assets/Cheerio/Cheerio.usd@ + variants = { + string modelingVariant = "CheerioB" + } + ) + { + float3 xformOp:rotateXYZ = (90.89801, -15.097648, 61.912357) + float3 xformOp:scale = (0.9856733, 0.98567325, 0.98567337) + double3 xformOp:translate = (85.4243439530625, -187.29888945562615, 90.51447739404878) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + } + + def "BowlD_1" ( + add references = @./assets/Bowl/Bowl.usd@ + variants = { + string modelingVariant = "BowlD" + } + ) + { + double3 xformOp:translate = (87.73756408691406, -180.12429809570312, 80.22386169433594) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + } + } + } + + def Xform "Ceiling_grp" ( + kind = "group" + ) + { + def "CeilingLight_1" ( + add references = @./assets/CeilingLight/CeilingLight.usd@ + ) + { + double3 xformOp:translate = (-29.264178037643433, -80.17690086364746, 252.77503542284325) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + } + } +} + diff --git a/testsuite/test_0016/data/LICENSE.txt b/testsuite/test_0016/data/LICENSE.txt new file mode 100755 index 0000000000..e6f682454b --- /dev/null +++ b/testsuite/test_0016/data/LICENSE.txt @@ -0,0 +1,48 @@ +USD KITCHEN ASSET END USER LICENSE AGREEMENT +PLEASE READ THE FOLLOWING USD KITCHEN ASSET END USER LICENSE AGREEMENT (THE “AGREEMENT”) CAREFULLY. THIS AGREEMENT BETWEEN YOU (“YOU” OR “YOUR”) AND PIXAR (“PIXAR,” “WE,” “OUR” OR “US”) SPECIFIES THE TERMS AND CONDITIONS REGARDING USE OF THE USD KITCHEN ASSET THAT IT ACCOMPANIES, INCLUDING ALL SOURCE CODE, COMPILED CODE, IMAGES, MODELS, DOCUMENTATION, DATA, AND OTHER MATERIALS (THE “USD KITCHEN ASSET”). +BY USING THE USD KITCHEN ASSET OR CLICKING ON THE “OK” BUTTON BELOW, YOU ARE ACCEPTING THIS AGREEMENT AND YOU ARE (1) REPRESENTING THAT YOU ARE OVER THE AGE OF 18, (2) REPRESENTING THAT YOU HAVE THE RIGHT AND AUTHORITY TO LEGALLY BIND YOURSELF OR YOUR COMPANY, AS APPLICABLE, AND (3) CONSENTING TO BE LEGALLY BOUND BY ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE TO THESE TERMS AND CONDITIONS OR CANNOT MAKE SUCH REPRESENTATIONS, YOU MAY NOT USE THE USD KITCHEN ASSET. +1. Grant of License. Subject to the restrictions set forth below, Pixar grants You a temporary, revocable, non-exclusive, nontransferable, nonsublicensable, nonassignable license to use the USD Kitchen Asset only for your personal, non-commercial testing of Pixar’s Universal Scene Description technology. All other uses of the USD Kitchen Asset by You are not permitted under this Agreement. + +2. Ownership. Pixar exclusively owns and shall retain all intellectual property rights in and to the USD Kitchen Asset and any derivative works based on the USD Kitchen Asset (“Derivative Works”). + +3. Restrictions. + +a. YOU MAY NOT (AND YOU AGREE NOT TO ALLOW A THIRD PARTY TO) RENT, LEASE, SUBLICENSE, SELL, ASSIGN, LOAN, USE FOR TIMESHARING OR SERVICE BUREAU PURPOSES, OR OTHERWISE TRANSFER THE USD KITCHEN ASSET, ANY DERIVATIVE WORKS, OR ANY OF YOUR RIGHTS AND OBLIGATIONS UNDER THIS AGREEMENT. + +b. You MAY NOT (and you agree not to allow a third party to) reverse engineer, decompile, disassemble, or attempt to reconstruct, identify, or discover any source code, underlying ideas, underlying user interface techniques, or algorithms from compiled portions of the USD Kitchen Asset by any means whatsoever, except to the extent the foregoing restrictions are expressly prohibited by applicable law. + +c. You MAY NOT (and you agree not to allow a third party to) use the USD Kitchen Asset or any Derivative Works for any production or commercial purpose, including but not limited to: (i) usage in the production of or usage in connection with feature films, television programming, online content, video games, advertising, videos, images, or other types of viewable content; and (ii) usage in the production of or usage in connection with physical or virtual products, including but not limited to vehicles, furniture, toys, graphic art, posters, clipart, physical models, stickers, clothing, 3D models, emoticons, and virtual goods. + +d. You MAY NOT (and you agree not to allow a third party to) remove or obscure any identification, copyright or other proprietary notices or markings from the USD Kitchen Asset. + +e. You MAY NOT (and you agree not to allow a third party to) distribute the USD Kitchen Asset or any Derivative Works without Pixar’s written authorization. + +f. You MAY NOT (and you agree not to allow a third party to) use the USD Kitchen Asset or any Derivative Works in an unlawful or unauthorized manner. + +Pixar reserves all rights in the USD Kitchen Asset and any Derivative Works not expressly granted hereunder. + +4. Feedback. You may provide feedback to Pixar concerning the USD Kitchen Asset from time to time, including, without limitation, identifying errors and potential improvements (the “Feedback”). You hereby grant to Pixar a worldwide, royalty-free, transferable, irrevocable and perpetual license, with the right to sublicense, use, modify, display, distribute, and otherwise exploit such Feedback without restriction, including, without limitation, utilizing and displaying such Feedback in connection with the USD Kitchen Asset and/or Pixar’s Universal Scene Description Project. + +5. No Publicity. Nothing in this Agreement grants you permission to use the trade names, trademarks, service marks, brands, designs, or product names of Pixar or its affiliates. + +6. No Warranty. THE USD KITCHEN ASSET IS PROVIDED ON AN “AS IS” BASIS. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, PIXAR AND/OR ITS LICENSORS DISCLAIM ALL WARRANTIES, EITHER ORAL OR WRITTEN, EITHER EXPRESS, IMPLIED, OR ARISING BY STATUTE, CUSTOM, COURSE OF DEALING, OR TRADE USAGE, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, QUALITY, ACCURACY, AND FITNESS FOR A PARTICULAR PURPOSE. + +7. Indemnification. You hereby agree to indemnify, defend, and hold Pixar and its affiliates and their officers, directors, owners, shareholders, employees, agents, information providers, licensors, and licensees (collectively, the "Indemnified Parties") harmless from and against any and all liabilities and costs (including reasonable attorneys' fees) incurred by the Indemnified Parties in connection with any claim arising out of any breach by you of this Agreement or your use of the USD Kitchen Asset or any Derivative Works. You shall use your best efforts to cooperate with us in the defense of any claim. We reserve the right, at our own expense, to assume the exclusive defense and control of any matter otherwise subject to indemnification by you. + +8. Limitation on Liability. UNDER NO CIRCUMSTANCES, INCLUDING, BUT NOT LIMITED TO, NEGLIGENCE, SHALL PIXAR AND/OR ITS LICENSORS BE LIABLE FOR ANY PERSONAL INJURY OR ANY INDIRECT, INCIDENTAL, SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES, INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, LOSS OF PROPERTY, LOSS OF DATA, OR BUSINESS INTERRUPTION UNDER ANY LEGAL THEORY (TORT, CONTRACT OR OTHERWISE), THAT RESULT FROM THE ACCESS OF, USE OF, OR THE INABILITY TO ACCESS OR USE THE USD KITCHEN ASSET OR ANY DERIVATIVE WORKS, EVEN IF WE HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. APPLICABLE LAW MAY NOT ALLOW THE LIMITATION OR EXCLUSION OF LIABILITY FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THE ABOVE LIMITATION OR EXCLUSION MAY NOT APPLY TO YOU. IN NO EVENT SHALL PIXAR’S AND/OR ITS LICENSOR’S TOTAL LIABILITY FOR ALL DAMAGES, LOSSES, AND CAUSES OF ACTION (WHETHER IN CONTRACT, TORT [INCLUDING, BUT NOT LIMITED TO, NEGLIGENCE], OR OTHERWISE) ARISING UNDER THIS AGREEMENT OR OUT OF THE USE OR INABILITY TO USE THE USD KITCHEN ASSET OR ANY DERIVATIVE WORKS EXCEED THE GREATER OF THE AMOUNT PAID BY YOU TO PIXAR, IF ANY, FOR ACCESSING AND/OR USING THE USD KITCHEN ASSET OR $50. THE PARTIES ACKNOWLEDGE THAT THIS IS A REASONABLE ALLOCATION OF RISK. + +9. Termination. This Agreement is effective until terminated by either party. Pixar reserves the right, in our sole discretion, to terminate your rights under this license at any time. Upon termination, you must cease use of the USD Kitchen Asset and any Derivative Works and remove the USD Kitchen Asset and any Derivative Works from all computer memories and storage devices within your possession or control. + +10. Survival. Sections 2-8 and 10-16 shall survive termination or expiration of this Agreement. + +11. Export Restrictions. You may not export or re-export the USD Kitchen Asset or any Derivative Works without (i) the prior written consent of Pixar; and (ii) complying with applicable export control laws and obtaining any necessary permits and licenses. + +12. Injunctive Relief. You acknowledge and agree that your breach of this Agreement, including any unauthorized use, transfer, distribution, sublicensing, or disclosure of the USD Kitchen Asset or any Derivative Works will cause irreparable injury to Pixar and/or its licensors, and under such circumstances, Pixar and/or its licensors shall be entitled to equitable relief, including without limitation preliminary and permanent injunctive relief, without being required to present evidence of such irreparable harm. You further acknowledge and agree that Pixar and/or its licensors shall be entitled to such equitable relief without being required to post a bond or other security. + +13. Relationship of Parties. The parties hereunder are independent contractors and this Agreement will not establish any relationship of partnership, joint venture, employment, franchise, or agency between You and Pixar. Neither party will have the power to bind the other or incur obligations on the other’s behalf without the other’s prior written consent, except as otherwise expressly provided herein. + +14. Assignment. You may not assign Your rights or delegate Your duties under this Agreement either in whole or in part, whether by merger, reorganization, sale of stock or assets, operation of law, or otherwise, without the prior written consent of Pixar. Any attempted assignment or delegation without such consent will be void. Pixar may assign its rights and obligations hereunder without restriction. + +15. Waiver. No waiver of any provision of this Agreement by us shall be deemed a further or continuing waiver of such provision or any other provision, and our failure to assert any right or provision under this Agreement shall not constitute a waiver of such right or provision. + +16. Entire Agreement. The terms of this Agreement shall be governed by and construed in accordance with the laws of the State of California, without giving effect to any principles of conflicts of law. You agree that any action at law or in equity arising out of or relating to this Agreement shall be filed only in the state or federal courts located in the city and county of San Francisco, California, and you hereby consent and submit to the personal jurisdiction of such courts for the purposes of litigating any such action. If any provision of these terms shall be unlawful, void, or for any reason unenforceable, then that provision shall be deemed severable from these terms and shall not affect the validity and enforceability of any remaining provisions. This Agreement supersedes in full all prior discussions and agreements between the parties relating to the subject matter hereof, and constitutes the entire agreement between the parties relating to the subject matter hereof. Pixar reserves the right to update, in its sole discretion, this Agreement at any time. Any such updates to the Agreement will be posted to the applicable Pixar website. Your continued use of the USD Kitchen Asset and/or any Derivative Works following posting by Pixar of the updated Agreement indicates your acceptance of the updated Agreement. Except for Pixar’s right to update this Agreement as specified in this section, any modifications to this Agreement must be made in writing and signed by both parties. diff --git a/testsuite/test_0016/data/README.txt b/testsuite/test_0016/data/README.txt new file mode 100755 index 0000000000..32a97e69ae --- /dev/null +++ b/testsuite/test_0016/data/README.txt @@ -0,0 +1,6 @@ +http://graphics.pixar.com/usd/downloads.html +*Copyright and Attribution* +Copyright © Disney/Pixar | Modeled by Christina Faraj based on concept art by Paul Felix for Lilo and Stitch. + +*Terms of Use* +These assets are property of Pixar. By downloading the project files you agree to the terms of use as defined in the LICENSE.txt file. \ No newline at end of file diff --git a/testsuite/test_0016/data/assets/Ball/Ball.geom.usd b/testsuite/test_0016/data/assets/Ball/Ball.geom.usd new file mode 100755 index 0000000000..89f19e9d0d Binary files /dev/null and b/testsuite/test_0016/data/assets/Ball/Ball.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Ball/Ball.usd b/testsuite/test_0016/data/assets/Ball/Ball.usd new file mode 100755 index 0000000000..dcb02d53f7 --- /dev/null +++ b/testsuite/test_0016/data/assets/Ball/Ball.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "Ball" + upAxis = "Z" +) + +def Xform "Ball" ( + assetInfo = { + asset identifier = @./assets/Ball/Ball.usd@ + string name = "Ball" + } + kind = "component" + payload = @./Ball_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Ball/Ball_payload.usd b/testsuite/test_0016/data/assets/Ball/Ball_payload.usd new file mode 100755 index 0000000000..e4c3c468a9 --- /dev/null +++ b/testsuite/test_0016/data/assets/Ball/Ball_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Ball" + upAxis = "Z" +) + +def "Ball" ( + assetInfo = { + asset identifier = @./assets/Ball/Ball.usd@ + string name = "Ball" + } + add references = @./Ball.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Book/Book.geom.usd b/testsuite/test_0016/data/assets/Book/Book.geom.usd new file mode 100755 index 0000000000..c259026b2d Binary files /dev/null and b/testsuite/test_0016/data/assets/Book/Book.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Book/Book.usd b/testsuite/test_0016/data/assets/Book/Book.usd new file mode 100755 index 0000000000..84a04b921e --- /dev/null +++ b/testsuite/test_0016/data/assets/Book/Book.usd @@ -0,0 +1,36 @@ +#usda 1.0 +( + defaultPrim = "Book" + upAxis = "Z" +) + +def Xform "Book" ( + assetInfo = { + asset identifier = @./assets/Book/Book.usd@ + string name = "Book" + } + kind = "component" + payload = @./Book_payload.usd@ + variants = { + string shadingVariant = "Default" + } + add variantSets = ["shadingVariant"] +) +{ + variantSet "shadingVariant" = { + "BookBlue" { + + } + "BookGreen" { + + } + "BookTan" { + + } + "Default" { + + } + } +} + + diff --git a/testsuite/test_0016/data/assets/Book/Book_payload.usd b/testsuite/test_0016/data/assets/Book/Book_payload.usd new file mode 100755 index 0000000000..ab79027577 --- /dev/null +++ b/testsuite/test_0016/data/assets/Book/Book_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Book" + upAxis = "Z" +) + +def "Book" ( + assetInfo = { + asset identifier = @./assets/Book/Book.usd@ + string name = "Book" + } + add references = @./Book.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Bottle/Bottle.geom.usd b/testsuite/test_0016/data/assets/Bottle/Bottle.geom.usd new file mode 100755 index 0000000000..caa21fc52a Binary files /dev/null and b/testsuite/test_0016/data/assets/Bottle/Bottle.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Bottle/Bottle.usd b/testsuite/test_0016/data/assets/Bottle/Bottle.usd new file mode 100755 index 0000000000..778f26d53e --- /dev/null +++ b/testsuite/test_0016/data/assets/Bottle/Bottle.usd @@ -0,0 +1,30 @@ +#usda 1.0 +( + defaultPrim = "Bottle" + upAxis = "Z" +) + +def Xform "Bottle" ( + assetInfo = { + asset identifier = @./assets/Bottle/Bottle.usd@ + string name = "Bottle" + } + kind = "component" + payload = @./Bottle_payload.usd@ + variants = { + string modelingVariant = "Tall" + } + add variantSets = ["modelingVariant"] +) +{ + variantSet "modelingVariant" = { + "Tall" { + + } + "Short" { + + } + } +} + + diff --git a/testsuite/test_0016/data/assets/Bottle/Bottle_payload.usd b/testsuite/test_0016/data/assets/Bottle/Bottle_payload.usd new file mode 100755 index 0000000000..1f79e06b63 --- /dev/null +++ b/testsuite/test_0016/data/assets/Bottle/Bottle_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Bottle" + upAxis = "Z" +) + +def "Bottle" ( + assetInfo = { + asset identifier = @./assets/Bottle/Bottle.usd@ + string name = "Bottle" + } + add references = @./Bottle.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/BottleB/BottleB.geom.usd b/testsuite/test_0016/data/assets/BottleB/BottleB.geom.usd new file mode 100755 index 0000000000..6d92259f16 Binary files /dev/null and b/testsuite/test_0016/data/assets/BottleB/BottleB.geom.usd differ diff --git a/testsuite/test_0016/data/assets/BottleB/BottleB.usd b/testsuite/test_0016/data/assets/BottleB/BottleB.usd new file mode 100755 index 0000000000..aaf724296d --- /dev/null +++ b/testsuite/test_0016/data/assets/BottleB/BottleB.usd @@ -0,0 +1,41 @@ +#usda 1.0 +( + defaultPrim = "BottleB" + upAxis = "Z" +) + +def Xform "BottleB" ( + assetInfo = { + asset identifier = @./assets/BottleB/BottleB.usd@ + string name = "BottleB" + } + kind = "component" + payload = @./BottleB_payload.usd@ + variants = { + string modelingVariant = "Large" + string shadingVariant = "Default" + } + add variantSets = ["shadingVariant", "modelingVariant"] +) +{ + variantSet "shadingVariant" = { + "Brown" { + } + "Default" { + } + "Green" { + } + "Rose" { + } + } + variantSet "modelingVariant" = { + "Large" { + } + "MediumNoCap" { + } + "Small" { + } + } +} + + diff --git a/testsuite/test_0016/data/assets/BottleB/BottleB_payload.usd b/testsuite/test_0016/data/assets/BottleB/BottleB_payload.usd new file mode 100755 index 0000000000..524c5c98ca --- /dev/null +++ b/testsuite/test_0016/data/assets/BottleB/BottleB_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "BottleB" + upAxis = "Z" +) + +def "BottleB" ( + assetInfo = { + asset identifier = @./assets/BottleB/BottleB.usd@ + string name = "BottleB" + } + add references = @./BottleB.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Bowl/Bowl.geom.usd b/testsuite/test_0016/data/assets/Bowl/Bowl.geom.usd new file mode 100755 index 0000000000..1ba59053ba Binary files /dev/null and b/testsuite/test_0016/data/assets/Bowl/Bowl.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Bowl/Bowl.usd b/testsuite/test_0016/data/assets/Bowl/Bowl.usd new file mode 100755 index 0000000000..9a312b73ee --- /dev/null +++ b/testsuite/test_0016/data/assets/Bowl/Bowl.usd @@ -0,0 +1,42 @@ +#usda 1.0 +( + defaultPrim = "Bowl" + upAxis = "Z" +) + +def Xform "Bowl" ( + assetInfo = { + asset identifier = @./assets/Bowl/Bowl.usd@ + string name = "Bowl" + } + kind = "component" + payload = @./Bowl_payload.usd@ + variants = { + string modelingVariant = "BowlA" + } + add variantSets = ["modelingVariant"] +) +{ + variantSet "modelingVariant" = { + "BowlA" { + + } + "BowlB" { + + } + "BowlC" { + + } + "BowlD" { + + } + "BowlE" { + + } + "BowlF" { + + } + } +} + + diff --git a/testsuite/test_0016/data/assets/Bowl/Bowl_payload.usd b/testsuite/test_0016/data/assets/Bowl/Bowl_payload.usd new file mode 100755 index 0000000000..64d9d4769e --- /dev/null +++ b/testsuite/test_0016/data/assets/Bowl/Bowl_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Bowl" + upAxis = "Z" +) + +def "Bowl" ( + assetInfo = { + asset identifier = @./assets/Bowl/Bowl.usd@ + string name = "Bowl" + } + add references = @./Bowl.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/BreadBag/BreadBag.geom.usd b/testsuite/test_0016/data/assets/BreadBag/BreadBag.geom.usd new file mode 100755 index 0000000000..a5c0947924 Binary files /dev/null and b/testsuite/test_0016/data/assets/BreadBag/BreadBag.geom.usd differ diff --git a/testsuite/test_0016/data/assets/BreadBag/BreadBag.usd b/testsuite/test_0016/data/assets/BreadBag/BreadBag.usd new file mode 100755 index 0000000000..cf824151f3 --- /dev/null +++ b/testsuite/test_0016/data/assets/BreadBag/BreadBag.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "BreadBag" + upAxis = "Z" +) + +def Xform "BreadBag" ( + assetInfo = { + asset identifier = @./assets/BreadBag/BreadBag.usd@ + string name = "BreadBag" + } + kind = "component" + payload = @./BreadBag_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/BreadBag/BreadBag_payload.usd b/testsuite/test_0016/data/assets/BreadBag/BreadBag_payload.usd new file mode 100755 index 0000000000..c6aea15645 --- /dev/null +++ b/testsuite/test_0016/data/assets/BreadBag/BreadBag_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "BreadBag" + upAxis = "Z" +) + +def "BreadBag" ( + assetInfo = { + asset identifier = @./assets/BreadBag/BreadBag.usd@ + string name = "BreadBag" + } + add references = @./BreadBag.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Broom/Broom.geom.usd b/testsuite/test_0016/data/assets/Broom/Broom.geom.usd new file mode 100755 index 0000000000..97c718881a Binary files /dev/null and b/testsuite/test_0016/data/assets/Broom/Broom.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Broom/Broom.usd b/testsuite/test_0016/data/assets/Broom/Broom.usd new file mode 100755 index 0000000000..d76fcf632f --- /dev/null +++ b/testsuite/test_0016/data/assets/Broom/Broom.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "Broom" + upAxis = "Z" +) + +def Xform "Broom" ( + assetInfo = { + asset identifier = @./assets/Broom/Broom.usd@ + string name = "Broom" + } + kind = "component" + payload = @./Broom_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Broom/Broom_payload.usd b/testsuite/test_0016/data/assets/Broom/Broom_payload.usd new file mode 100755 index 0000000000..d69163b085 --- /dev/null +++ b/testsuite/test_0016/data/assets/Broom/Broom_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Broom" + upAxis = "Z" +) + +def "Broom" ( + assetInfo = { + asset identifier = @./assets/Broom/Broom.usd@ + string name = "Broom" + } + add references = @./Broom.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/CastIron/CastIron.geom.usd b/testsuite/test_0016/data/assets/CastIron/CastIron.geom.usd new file mode 100755 index 0000000000..35631cb120 Binary files /dev/null and b/testsuite/test_0016/data/assets/CastIron/CastIron.geom.usd differ diff --git a/testsuite/test_0016/data/assets/CastIron/CastIron.usd b/testsuite/test_0016/data/assets/CastIron/CastIron.usd new file mode 100755 index 0000000000..75f8dca037 --- /dev/null +++ b/testsuite/test_0016/data/assets/CastIron/CastIron.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "CastIron" + upAxis = "Z" +) + +def Xform "CastIron" ( + assetInfo = { + asset identifier = @./assets/CastIron/CastIron.usd@ + string name = "CastIron" + } + kind = "component" + payload = @./CastIron_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/CastIron/CastIron_payload.usd b/testsuite/test_0016/data/assets/CastIron/CastIron_payload.usd new file mode 100755 index 0000000000..d4e0526120 --- /dev/null +++ b/testsuite/test_0016/data/assets/CastIron/CastIron_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "CastIron" + upAxis = "Z" +) + +def "CastIron" ( + assetInfo = { + asset identifier = @./assets/CastIron/CastIron.usd@ + string name = "CastIron" + } + add references = @./CastIron.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/CeilingLight/CeilingLight.geom.usd b/testsuite/test_0016/data/assets/CeilingLight/CeilingLight.geom.usd new file mode 100755 index 0000000000..716020d91f Binary files /dev/null and b/testsuite/test_0016/data/assets/CeilingLight/CeilingLight.geom.usd differ diff --git a/testsuite/test_0016/data/assets/CeilingLight/CeilingLight.usd b/testsuite/test_0016/data/assets/CeilingLight/CeilingLight.usd new file mode 100755 index 0000000000..14bb11086c --- /dev/null +++ b/testsuite/test_0016/data/assets/CeilingLight/CeilingLight.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "CeilingLight" + upAxis = "Z" +) + +def Xform "CeilingLight" ( + assetInfo = { + asset identifier = @./assets/CeilingLight/CeilingLight.usd@ + string name = "CeilingLight" + } + kind = "component" + payload = @./CeilingLight_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/CeilingLight/CeilingLight_payload.usd b/testsuite/test_0016/data/assets/CeilingLight/CeilingLight_payload.usd new file mode 100755 index 0000000000..a3822b1dc3 --- /dev/null +++ b/testsuite/test_0016/data/assets/CeilingLight/CeilingLight_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "CeilingLight" + upAxis = "Z" +) + +def "CeilingLight" ( + assetInfo = { + asset identifier = @./assets/CeilingLight/CeilingLight.usd@ + string name = "CeilingLight" + } + add references = @./CeilingLight.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/CerealBox/CerealBox.geom.usd b/testsuite/test_0016/data/assets/CerealBox/CerealBox.geom.usd new file mode 100755 index 0000000000..c7cb3c06fd Binary files /dev/null and b/testsuite/test_0016/data/assets/CerealBox/CerealBox.geom.usd differ diff --git a/testsuite/test_0016/data/assets/CerealBox/CerealBox.usd b/testsuite/test_0016/data/assets/CerealBox/CerealBox.usd new file mode 100755 index 0000000000..d792a6c6ff --- /dev/null +++ b/testsuite/test_0016/data/assets/CerealBox/CerealBox.usd @@ -0,0 +1,30 @@ +#usda 1.0 +( + defaultPrim = "CerealBox" + upAxis = "Z" +) + +def Xform "CerealBox" ( + assetInfo = { + asset identifier = @./assets/CerealBox/CerealBox.usd@ + string name = "CerealBox" + } + kind = "component" + payload = @./CerealBox_payload.usd@ + variants = { + string modelingVariant = "CerealBoxA" + } + add variantSets = ["modelingVariant"] +) +{ + variantSet "modelingVariant" = { + "CerealBoxA" { + + } + "CerealBoxB" { + + } + } +} + + diff --git a/testsuite/test_0016/data/assets/CerealBox/CerealBox_payload.usd b/testsuite/test_0016/data/assets/CerealBox/CerealBox_payload.usd new file mode 100755 index 0000000000..7cd4ad342c --- /dev/null +++ b/testsuite/test_0016/data/assets/CerealBox/CerealBox_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "CerealBox" + upAxis = "Z" +) + +def "CerealBox" ( + assetInfo = { + asset identifier = @./assets/CerealBox/CerealBox.usd@ + string name = "CerealBox" + } + add references = @./CerealBox.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Chair/Chair.geom.usd b/testsuite/test_0016/data/assets/Chair/Chair.geom.usd new file mode 100755 index 0000000000..33578b6f2b Binary files /dev/null and b/testsuite/test_0016/data/assets/Chair/Chair.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Chair/Chair.usd b/testsuite/test_0016/data/assets/Chair/Chair.usd new file mode 100755 index 0000000000..4e04d503e6 --- /dev/null +++ b/testsuite/test_0016/data/assets/Chair/Chair.usd @@ -0,0 +1,30 @@ +#usda 1.0 +( + defaultPrim = "Chair" + upAxis = "Z" +) + +def Xform "Chair" ( + assetInfo = { + asset identifier = @./assets/Chair/Chair.usd@ + string name = "Chair" + } + kind = "component" + payload = @./Chair_payload.usd@ + variants = { + string modelingVariant = "ChairA" + } + add variantSets = ["modelingVariant"] +) +{ + variantSet "modelingVariant" = { + "ChairA" { + + } + "ChairB" { + + } + } +} + + diff --git a/testsuite/test_0016/data/assets/Chair/Chair_payload.usd b/testsuite/test_0016/data/assets/Chair/Chair_payload.usd new file mode 100755 index 0000000000..743498fd17 --- /dev/null +++ b/testsuite/test_0016/data/assets/Chair/Chair_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Chair" + upAxis = "Z" +) + +def "Chair" ( + assetInfo = { + asset identifier = @./assets/Chair/Chair.usd@ + string name = "Chair" + } + add references = @./Chair.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Cheerio/Cheerio.geom.usd b/testsuite/test_0016/data/assets/Cheerio/Cheerio.geom.usd new file mode 100755 index 0000000000..53239f2f27 Binary files /dev/null and b/testsuite/test_0016/data/assets/Cheerio/Cheerio.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Cheerio/Cheerio.usd b/testsuite/test_0016/data/assets/Cheerio/Cheerio.usd new file mode 100755 index 0000000000..c4cbfe4003 --- /dev/null +++ b/testsuite/test_0016/data/assets/Cheerio/Cheerio.usd @@ -0,0 +1,30 @@ +#usda 1.0 +( + defaultPrim = "Cheerio" + upAxis = "Z" +) + +def Xform "Cheerio" ( + assetInfo = { + asset identifier = @./assets/Cheerio/Cheerio.usd@ + string name = "Cheerio" + } + kind = "component" + payload = @./Cheerio_payload.usd@ + variants = { + string modelingVariant = "CheerioA" + } + add variantSets = ["modelingVariant"] +) +{ + variantSet "modelingVariant" = { + "CheerioA" { + + } + "CheerioB" { + + } + } +} + + diff --git a/testsuite/test_0016/data/assets/Cheerio/Cheerio_payload.usd b/testsuite/test_0016/data/assets/Cheerio/Cheerio_payload.usd new file mode 100755 index 0000000000..9d42937d05 --- /dev/null +++ b/testsuite/test_0016/data/assets/Cheerio/Cheerio_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Cheerio" + upAxis = "Z" +) + +def "Cheerio" ( + assetInfo = { + asset identifier = @./assets/Cheerio/Cheerio.usd@ + string name = "Cheerio" + } + add references = @./Cheerio.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Clock/Clock.geom.usd b/testsuite/test_0016/data/assets/Clock/Clock.geom.usd new file mode 100755 index 0000000000..efe4954f9e Binary files /dev/null and b/testsuite/test_0016/data/assets/Clock/Clock.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Clock/Clock.usd b/testsuite/test_0016/data/assets/Clock/Clock.usd new file mode 100755 index 0000000000..eef24f6bf4 --- /dev/null +++ b/testsuite/test_0016/data/assets/Clock/Clock.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "Clock" + upAxis = "Z" +) + +def Xform "Clock" ( + assetInfo = { + asset identifier = @./assets/Clock/Clock.usd@ + string name = "Clock" + } + kind = "component" + payload = @./Clock_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Clock/Clock_payload.usd b/testsuite/test_0016/data/assets/Clock/Clock_payload.usd new file mode 100755 index 0000000000..d010d5358c --- /dev/null +++ b/testsuite/test_0016/data/assets/Clock/Clock_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Clock" + upAxis = "Z" +) + +def "Clock" ( + assetInfo = { + asset identifier = @./assets/Clock/Clock.usd@ + string name = "Clock" + } + add references = @./Clock.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Crayon/Crayon.geom.usd b/testsuite/test_0016/data/assets/Crayon/Crayon.geom.usd new file mode 100755 index 0000000000..cff65e2a74 Binary files /dev/null and b/testsuite/test_0016/data/assets/Crayon/Crayon.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Crayon/Crayon.usd b/testsuite/test_0016/data/assets/Crayon/Crayon.usd new file mode 100755 index 0000000000..24e217c4e8 --- /dev/null +++ b/testsuite/test_0016/data/assets/Crayon/Crayon.usd @@ -0,0 +1,55 @@ +#usda 1.0 +( + defaultPrim = "Crayon" + upAxis = "Z" +) + +def Xform "Crayon" ( + assetInfo = { + asset identifier = @./assets/Crayon/Crayon.usd@ + string name = "Crayon" + } + kind = "component" + payload = @./Crayon_payload.usd@ + variants = { + string modelingVariant = "Crayon" + string shadingVariant = "Default" + } + add variantSets = ["shadingVariant", "modelingVariant"] +) +{ + variantSet "shadingVariant" = { + "Blue" { + + } + "Default" { + + } + "Green" { + + } + "Orange" { + + } + "Purple" { + + } + "Red" { + + } + "Yellow" { + + } + } + + variantSet "modelingVariant" = { + "Crayon" { + + } + "CrayonWorn" { + + } + } +} + + diff --git a/testsuite/test_0016/data/assets/Crayon/Crayon_payload.usd b/testsuite/test_0016/data/assets/Crayon/Crayon_payload.usd new file mode 100755 index 0000000000..5604db55cd --- /dev/null +++ b/testsuite/test_0016/data/assets/Crayon/Crayon_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Crayon" + upAxis = "Z" +) + +def "Crayon" ( + assetInfo = { + asset identifier = @./assets/Crayon/Crayon.usd@ + string name = "Crayon" + } + add references = @./Crayon.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Cup/Cup.geom.usd b/testsuite/test_0016/data/assets/Cup/Cup.geom.usd new file mode 100755 index 0000000000..c072d09263 Binary files /dev/null and b/testsuite/test_0016/data/assets/Cup/Cup.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Cup/Cup.usd b/testsuite/test_0016/data/assets/Cup/Cup.usd new file mode 100755 index 0000000000..7da0321ba3 --- /dev/null +++ b/testsuite/test_0016/data/assets/Cup/Cup.usd @@ -0,0 +1,48 @@ +#usda 1.0 +( + defaultPrim = "Cup" + upAxis = "Z" +) + +def Xform "Cup" ( + assetInfo = { + asset identifier = @./assets/Cup/Cup.usd@ + string name = "Cup" + } + kind = "component" + payload = @./Cup_payload.usd@ + variants = { + string modelingVariant = "CupA" + string shadingVariant = "Default" + } + add variantSets = ["shadingVariant", "modelingVariant"] +) +{ + variantSet "shadingVariant" = { + "Blue" { + + } + "Default" { + + } + "Red" { + + } + } + variantSet "modelingVariant" = { + "CupA" { + + } + "CupB" { + + } + "CupC" { + + } + "CupD" { + + } + } +} + + diff --git a/testsuite/test_0016/data/assets/Cup/Cup_payload.usd b/testsuite/test_0016/data/assets/Cup/Cup_payload.usd new file mode 100755 index 0000000000..2f44cc6e2f --- /dev/null +++ b/testsuite/test_0016/data/assets/Cup/Cup_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Cup" + upAxis = "Z" +) + +def "Cup" ( + assetInfo = { + asset identifier = @./assets/Cup/Cup.usd@ + string name = "Cup" + } + add references = @./Cup.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/DinnerMat/DinnerMat.geom.usd b/testsuite/test_0016/data/assets/DinnerMat/DinnerMat.geom.usd new file mode 100755 index 0000000000..2371561b6e Binary files /dev/null and b/testsuite/test_0016/data/assets/DinnerMat/DinnerMat.geom.usd differ diff --git a/testsuite/test_0016/data/assets/DinnerMat/DinnerMat.usd b/testsuite/test_0016/data/assets/DinnerMat/DinnerMat.usd new file mode 100755 index 0000000000..85d3e65692 --- /dev/null +++ b/testsuite/test_0016/data/assets/DinnerMat/DinnerMat.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "DinnerMat" + upAxis = "Z" +) + +def Xform "DinnerMat" ( + assetInfo = { + asset identifier = @./assets/DinnerMat/DinnerMat.usd@ + string name = "DinnerMat" + } + kind = "component" + payload = @./DinnerMat_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/DinnerMat/DinnerMat_payload.usd b/testsuite/test_0016/data/assets/DinnerMat/DinnerMat_payload.usd new file mode 100755 index 0000000000..3701f009e4 --- /dev/null +++ b/testsuite/test_0016/data/assets/DinnerMat/DinnerMat_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "DinnerMat" + upAxis = "Z" +) + +def "DinnerMat" ( + assetInfo = { + asset identifier = @./assets/DinnerMat/DinnerMat.usd@ + string name = "DinnerMat" + } + add references = @./DinnerMat.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/DustPan/DustPan.geom.usd b/testsuite/test_0016/data/assets/DustPan/DustPan.geom.usd new file mode 100755 index 0000000000..2a2512fe1b Binary files /dev/null and b/testsuite/test_0016/data/assets/DustPan/DustPan.geom.usd differ diff --git a/testsuite/test_0016/data/assets/DustPan/DustPan.usd b/testsuite/test_0016/data/assets/DustPan/DustPan.usd new file mode 100755 index 0000000000..9f1c263c67 --- /dev/null +++ b/testsuite/test_0016/data/assets/DustPan/DustPan.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "DustPan" + upAxis = "Z" +) + +def Xform "DustPan" ( + assetInfo = { + asset identifier = @./assets/DustPan/DustPan.usd@ + string name = "DustPan" + } + kind = "component" + payload = @./DustPan_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/DustPan/DustPan_payload.usd b/testsuite/test_0016/data/assets/DustPan/DustPan_payload.usd new file mode 100755 index 0000000000..e4a5aee074 --- /dev/null +++ b/testsuite/test_0016/data/assets/DustPan/DustPan_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "DustPan" + upAxis = "Z" +) + +def "DustPan" ( + assetInfo = { + asset identifier = @./assets/DustPan/DustPan.usd@ + string name = "DustPan" + } + add references = @./DustPan.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/FlowerPot/FlowerPot.geom.usd b/testsuite/test_0016/data/assets/FlowerPot/FlowerPot.geom.usd new file mode 100755 index 0000000000..24308b309d Binary files /dev/null and b/testsuite/test_0016/data/assets/FlowerPot/FlowerPot.geom.usd differ diff --git a/testsuite/test_0016/data/assets/FlowerPot/FlowerPot.usd b/testsuite/test_0016/data/assets/FlowerPot/FlowerPot.usd new file mode 100755 index 0000000000..324bc4c09d --- /dev/null +++ b/testsuite/test_0016/data/assets/FlowerPot/FlowerPot.usd @@ -0,0 +1,30 @@ +#usda 1.0 +( + defaultPrim = "FlowerPot" + upAxis = "Z" +) + +def Xform "FlowerPot" ( + assetInfo = { + asset identifier = @./assets/FlowerPot/FlowerPot.usd@ + string name = "FlowerPot" + } + kind = "component" + payload = @./FlowerPot_payload.usd@ + variants = { + string modelingVariant = "FlowerPotA" + } + add variantSets = ["modelingVariant"] +) +{ + variantSet "modelingVariant" = { + "FlowerPotA" { + + } + "FlowerPotB" { + + } + } +} + + diff --git a/testsuite/test_0016/data/assets/FlowerPot/FlowerPot_payload.usd b/testsuite/test_0016/data/assets/FlowerPot/FlowerPot_payload.usd new file mode 100755 index 0000000000..20ea6867ca --- /dev/null +++ b/testsuite/test_0016/data/assets/FlowerPot/FlowerPot_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "FlowerPot" + upAxis = "Z" +) + +def "FlowerPot" ( + assetInfo = { + asset identifier = @./assets/FlowerPot/FlowerPot.usd@ + string name = "FlowerPot" + } + add references = @./FlowerPot.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/FoldingTable/FoldingTable.geom.usd b/testsuite/test_0016/data/assets/FoldingTable/FoldingTable.geom.usd new file mode 100755 index 0000000000..34c346864e Binary files /dev/null and b/testsuite/test_0016/data/assets/FoldingTable/FoldingTable.geom.usd differ diff --git a/testsuite/test_0016/data/assets/FoldingTable/FoldingTable.usd b/testsuite/test_0016/data/assets/FoldingTable/FoldingTable.usd new file mode 100755 index 0000000000..0ac287d7b4 --- /dev/null +++ b/testsuite/test_0016/data/assets/FoldingTable/FoldingTable.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "FoldingTable" + upAxis = "Z" +) + +def Xform "FoldingTable" ( + assetInfo = { + asset identifier = @./assets/FoldingTable/FoldingTable.usd@ + string name = "FoldingTable" + } + kind = "component" + payload = @./FoldingTable_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/FoldingTable/FoldingTable_payload.usd b/testsuite/test_0016/data/assets/FoldingTable/FoldingTable_payload.usd new file mode 100755 index 0000000000..648dd7ab64 --- /dev/null +++ b/testsuite/test_0016/data/assets/FoldingTable/FoldingTable_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "FoldingTable" + upAxis = "Z" +) + +def "FoldingTable" ( + assetInfo = { + asset identifier = @./assets/FoldingTable/FoldingTable.usd@ + string name = "FoldingTable" + } + add references = @./FoldingTable.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Fork/Fork.geom.usd b/testsuite/test_0016/data/assets/Fork/Fork.geom.usd new file mode 100755 index 0000000000..9f5c58c6d7 Binary files /dev/null and b/testsuite/test_0016/data/assets/Fork/Fork.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Fork/Fork.usd b/testsuite/test_0016/data/assets/Fork/Fork.usd new file mode 100755 index 0000000000..20b20f8b27 --- /dev/null +++ b/testsuite/test_0016/data/assets/Fork/Fork.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "Fork" + upAxis = "Z" +) + +def Xform "Fork" ( + assetInfo = { + asset identifier = @./assets/Fork/Fork.usd@ + string name = "Fork" + } + kind = "component" + payload = @./Fork_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Fork/Fork_payload.usd b/testsuite/test_0016/data/assets/Fork/Fork_payload.usd new file mode 100755 index 0000000000..d56f9cc43a --- /dev/null +++ b/testsuite/test_0016/data/assets/Fork/Fork_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Fork" + upAxis = "Z" +) + +def "Fork" ( + assetInfo = { + asset identifier = @./assets/Fork/Fork.usd@ + string name = "Fork" + } + add references = @./Fork.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/FramePicture/FramePicture.geom.usd b/testsuite/test_0016/data/assets/FramePicture/FramePicture.geom.usd new file mode 100755 index 0000000000..42e743269b Binary files /dev/null and b/testsuite/test_0016/data/assets/FramePicture/FramePicture.geom.usd differ diff --git a/testsuite/test_0016/data/assets/FramePicture/FramePicture.usd b/testsuite/test_0016/data/assets/FramePicture/FramePicture.usd new file mode 100755 index 0000000000..b619a53966 --- /dev/null +++ b/testsuite/test_0016/data/assets/FramePicture/FramePicture.usd @@ -0,0 +1,36 @@ +#usda 1.0 +( + defaultPrim = "FramePicture" + upAxis = "Z" +) + +def Xform "FramePicture" ( + assetInfo = { + asset identifier = @./assets/FramePicture/FramePicture.usd@ + string name = "FramePicture" + } + kind = "component" + payload = @./FramePicture_payload.usd@ + variants = { + string modelingVariant = "FramePictureA" + } + add variantSets = ["modelingVariant"] +) +{ + variantSet "modelingVariant" = { + "FramePictureA" { + + } + "FramePictureB" { + + } + "FramePictureC" { + + } + "FramePictureD" { + + } + } +} + + diff --git a/testsuite/test_0016/data/assets/FramePicture/FramePicture_payload.usd b/testsuite/test_0016/data/assets/FramePicture/FramePicture_payload.usd new file mode 100755 index 0000000000..8909cbee43 --- /dev/null +++ b/testsuite/test_0016/data/assets/FramePicture/FramePicture_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "FramePicture" + upAxis = "Z" +) + +def "FramePicture" ( + assetInfo = { + asset identifier = @./assets/FramePicture/FramePicture.usd@ + string name = "FramePicture" + } + add references = @./FramePicture.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/FramePictureOval/FramePictureOval.geom.usd b/testsuite/test_0016/data/assets/FramePictureOval/FramePictureOval.geom.usd new file mode 100755 index 0000000000..c6459ea45b Binary files /dev/null and b/testsuite/test_0016/data/assets/FramePictureOval/FramePictureOval.geom.usd differ diff --git a/testsuite/test_0016/data/assets/FramePictureOval/FramePictureOval.usd b/testsuite/test_0016/data/assets/FramePictureOval/FramePictureOval.usd new file mode 100755 index 0000000000..4a6165068e --- /dev/null +++ b/testsuite/test_0016/data/assets/FramePictureOval/FramePictureOval.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "FramePictureOval" + upAxis = "Z" +) + +def Xform "FramePictureOval" ( + assetInfo = { + asset identifier = @./assets/FramePictureOval/FramePictureOval.usd@ + string name = "FramePictureOval" + } + kind = "component" + payload = @./FramePictureOval_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/FramePictureOval/FramePictureOval_payload.usd b/testsuite/test_0016/data/assets/FramePictureOval/FramePictureOval_payload.usd new file mode 100755 index 0000000000..5446b902e1 --- /dev/null +++ b/testsuite/test_0016/data/assets/FramePictureOval/FramePictureOval_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "FramePictureOval" + upAxis = "Z" +) + +def "FramePictureOval" ( + assetInfo = { + asset identifier = @./assets/FramePictureOval/FramePictureOval.usd@ + string name = "FramePictureOval" + } + add references = @./FramePictureOval.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/GarlicRope/GarlicRope.geom.usd b/testsuite/test_0016/data/assets/GarlicRope/GarlicRope.geom.usd new file mode 100755 index 0000000000..0f5a97ac7b Binary files /dev/null and b/testsuite/test_0016/data/assets/GarlicRope/GarlicRope.geom.usd differ diff --git a/testsuite/test_0016/data/assets/GarlicRope/GarlicRope.usd b/testsuite/test_0016/data/assets/GarlicRope/GarlicRope.usd new file mode 100755 index 0000000000..ad12ec9327 --- /dev/null +++ b/testsuite/test_0016/data/assets/GarlicRope/GarlicRope.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "GarlicRope" + upAxis = "Z" +) + +def Xform "GarlicRope" ( + assetInfo = { + asset identifier = @./assets/GarlicRope/GarlicRope.usd@ + string name = "GarlicRope" + } + kind = "component" + payload = @./GarlicRope_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/GarlicRope/GarlicRope_payload.usd b/testsuite/test_0016/data/assets/GarlicRope/GarlicRope_payload.usd new file mode 100755 index 0000000000..e56cfd3b30 --- /dev/null +++ b/testsuite/test_0016/data/assets/GarlicRope/GarlicRope_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "GarlicRope" + upAxis = "Z" +) + +def "GarlicRope" ( + assetInfo = { + asset identifier = @./assets/GarlicRope/GarlicRope.usd@ + string name = "GarlicRope" + } + add references = @./GarlicRope.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/HandTowel/HandTowel.geom.usd b/testsuite/test_0016/data/assets/HandTowel/HandTowel.geom.usd new file mode 100755 index 0000000000..8eda1865ca Binary files /dev/null and b/testsuite/test_0016/data/assets/HandTowel/HandTowel.geom.usd differ diff --git a/testsuite/test_0016/data/assets/HandTowel/HandTowel.usd b/testsuite/test_0016/data/assets/HandTowel/HandTowel.usd new file mode 100755 index 0000000000..cc7ce1fcde --- /dev/null +++ b/testsuite/test_0016/data/assets/HandTowel/HandTowel.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "HandTowel" + upAxis = "Z" +) + +def Xform "HandTowel" ( + assetInfo = { + asset identifier = @./assets/HandTowel/HandTowel.usd@ + string name = "HandTowel" + } + kind = "component" + payload = @./HandTowel_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/HandTowel/HandTowel_payload.usd b/testsuite/test_0016/data/assets/HandTowel/HandTowel_payload.usd new file mode 100755 index 0000000000..eafd2445f4 --- /dev/null +++ b/testsuite/test_0016/data/assets/HandTowel/HandTowel_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "HandTowel" + upAxis = "Z" +) + +def "HandTowel" ( + assetInfo = { + asset identifier = @./assets/HandTowel/HandTowel.usd@ + string name = "HandTowel" + } + add references = @./HandTowel.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Hanger/Hanger.geom.usd b/testsuite/test_0016/data/assets/Hanger/Hanger.geom.usd new file mode 100755 index 0000000000..5506a7ac92 Binary files /dev/null and b/testsuite/test_0016/data/assets/Hanger/Hanger.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Hanger/Hanger.usd b/testsuite/test_0016/data/assets/Hanger/Hanger.usd new file mode 100755 index 0000000000..968a95da44 --- /dev/null +++ b/testsuite/test_0016/data/assets/Hanger/Hanger.usd @@ -0,0 +1,33 @@ +#usda 1.0 +( + defaultPrim = "Hanger" + upAxis = "Z" +) + +def Xform "Hanger" ( + assetInfo = { + asset identifier = @./assets/Hanger/Hanger.usd@ + string name = "Hanger" + } + kind = "component" + payload = @./Hanger_payload.usd@ + variants = { + string shadingVariant = "Default" + } + add variantSets = ["shadingVariant"] +) +{ + variantSet "shadingVariant" = { + "Default" { + + } + "LightBrown" { + + } + "LightBrownDirty" { + + } + } +} + + diff --git a/testsuite/test_0016/data/assets/Hanger/Hanger_payload.usd b/testsuite/test_0016/data/assets/Hanger/Hanger_payload.usd new file mode 100755 index 0000000000..cac3db57d0 --- /dev/null +++ b/testsuite/test_0016/data/assets/Hanger/Hanger_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Hanger" + upAxis = "Z" +) + +def "Hanger" ( + assetInfo = { + asset identifier = @./assets/Hanger/Hanger.usd@ + string name = "Hanger" + } + add references = @./Hanger.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Hook/Hook.geom.usd b/testsuite/test_0016/data/assets/Hook/Hook.geom.usd new file mode 100755 index 0000000000..18445a1be8 Binary files /dev/null and b/testsuite/test_0016/data/assets/Hook/Hook.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Hook/Hook.usd b/testsuite/test_0016/data/assets/Hook/Hook.usd new file mode 100755 index 0000000000..a8a584be59 --- /dev/null +++ b/testsuite/test_0016/data/assets/Hook/Hook.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "Hook" + upAxis = "Z" +) + +def Xform "Hook" ( + assetInfo = { + asset identifier = @./assets/Hook/Hook.usd@ + string name = "Hook" + } + kind = "component" + payload = @./Hook_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Hook/Hook_payload.usd b/testsuite/test_0016/data/assets/Hook/Hook_payload.usd new file mode 100755 index 0000000000..01cebee60a --- /dev/null +++ b/testsuite/test_0016/data/assets/Hook/Hook_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Hook" + upAxis = "Z" +) + +def "Hook" ( + assetInfo = { + asset identifier = @./assets/Hook/Hook.usd@ + string name = "Hook" + } + add references = @./Hook.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Iron/Iron.geom.usd b/testsuite/test_0016/data/assets/Iron/Iron.geom.usd new file mode 100755 index 0000000000..9db0cf355e Binary files /dev/null and b/testsuite/test_0016/data/assets/Iron/Iron.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Iron/Iron.usd b/testsuite/test_0016/data/assets/Iron/Iron.usd new file mode 100755 index 0000000000..9647197da8 --- /dev/null +++ b/testsuite/test_0016/data/assets/Iron/Iron.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "Iron" + upAxis = "Z" +) + +def Xform "Iron" ( + assetInfo = { + asset identifier = @./assets/Iron/Iron.usd@ + string name = "Iron" + } + kind = "component" + payload = @./Iron_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Iron/Iron_payload.usd b/testsuite/test_0016/data/assets/Iron/Iron_payload.usd new file mode 100755 index 0000000000..17ab3633f7 --- /dev/null +++ b/testsuite/test_0016/data/assets/Iron/Iron_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Iron" + upAxis = "Z" +) + +def "Iron" ( + assetInfo = { + asset identifier = @./assets/Iron/Iron.usd@ + string name = "Iron" + } + add references = @./Iron.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/IronBoard/IronBoard.geom.usd b/testsuite/test_0016/data/assets/IronBoard/IronBoard.geom.usd new file mode 100755 index 0000000000..4d8811896c Binary files /dev/null and b/testsuite/test_0016/data/assets/IronBoard/IronBoard.geom.usd differ diff --git a/testsuite/test_0016/data/assets/IronBoard/IronBoard.usd b/testsuite/test_0016/data/assets/IronBoard/IronBoard.usd new file mode 100755 index 0000000000..e7c349641d --- /dev/null +++ b/testsuite/test_0016/data/assets/IronBoard/IronBoard.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "IronBoard" + upAxis = "Z" +) + +def Xform "IronBoard" ( + assetInfo = { + asset identifier = @./assets/IronBoard/IronBoard.usd@ + string name = "IronBoard" + } + kind = "component" + payload = @./IronBoard_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/IronBoard/IronBoard_payload.usd b/testsuite/test_0016/data/assets/IronBoard/IronBoard_payload.usd new file mode 100755 index 0000000000..ffb3415ffa --- /dev/null +++ b/testsuite/test_0016/data/assets/IronBoard/IronBoard_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "IronBoard" + upAxis = "Z" +) + +def "IronBoard" ( + assetInfo = { + asset identifier = @./assets/IronBoard/IronBoard.usd@ + string name = "IronBoard" + } + add references = @./IronBoard.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Jar/Jar.geom.usd b/testsuite/test_0016/data/assets/Jar/Jar.geom.usd new file mode 100755 index 0000000000..1e83247e49 Binary files /dev/null and b/testsuite/test_0016/data/assets/Jar/Jar.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Jar/Jar.usd b/testsuite/test_0016/data/assets/Jar/Jar.usd new file mode 100755 index 0000000000..2c07f7172e --- /dev/null +++ b/testsuite/test_0016/data/assets/Jar/Jar.usd @@ -0,0 +1,30 @@ +#usda 1.0 +( + defaultPrim = "Jar" + upAxis = "Z" +) + +def Xform "Jar" ( + assetInfo = { + asset identifier = @./assets/Jar/Jar.usd@ + string name = "Jar" + } + kind = "component" + payload = @./Jar_payload.usd@ + variants = { + string modelingVariant = "JarA" + } + add variantSets = ["modelingVariant"] +) +{ + variantSet "modelingVariant" = { + "JarA" { + + } + "JarB" { + + } + } +} + + diff --git a/testsuite/test_0016/data/assets/Jar/Jar_payload.usd b/testsuite/test_0016/data/assets/Jar/Jar_payload.usd new file mode 100755 index 0000000000..5d3f151d87 --- /dev/null +++ b/testsuite/test_0016/data/assets/Jar/Jar_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Jar" + upAxis = "Z" +) + +def "Jar" ( + assetInfo = { + asset identifier = @./assets/Jar/Jar.usd@ + string name = "Jar" + } + add references = @./Jar.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Kitchen/Kitchen.geom.usd b/testsuite/test_0016/data/assets/Kitchen/Kitchen.geom.usd new file mode 100755 index 0000000000..22e9ccc693 Binary files /dev/null and b/testsuite/test_0016/data/assets/Kitchen/Kitchen.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Kitchen/Kitchen.usd b/testsuite/test_0016/data/assets/Kitchen/Kitchen.usd new file mode 100755 index 0000000000..820372f4bc --- /dev/null +++ b/testsuite/test_0016/data/assets/Kitchen/Kitchen.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "Kitchen" + upAxis = "Z" +) + +def Xform "Kitchen" ( + assetInfo = { + asset identifier = @./assets/Kitchen/Kitchen.usd@ + string name = "Kitchen" + } + kind = "component" + payload = @./Kitchen_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Kitchen/Kitchen_payload.usd b/testsuite/test_0016/data/assets/Kitchen/Kitchen_payload.usd new file mode 100755 index 0000000000..50694ebc6a --- /dev/null +++ b/testsuite/test_0016/data/assets/Kitchen/Kitchen_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Kitchen" + upAxis = "Z" +) + +def "Kitchen" ( + assetInfo = { + asset identifier = @./assets/Kitchen/Kitchen.usd@ + string name = "Kitchen" + } + add references = @./Kitchen.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/KitchenTable/KitchenTable.geom.usd b/testsuite/test_0016/data/assets/KitchenTable/KitchenTable.geom.usd new file mode 100755 index 0000000000..8e8355182b Binary files /dev/null and b/testsuite/test_0016/data/assets/KitchenTable/KitchenTable.geom.usd differ diff --git a/testsuite/test_0016/data/assets/KitchenTable/KitchenTable.usd b/testsuite/test_0016/data/assets/KitchenTable/KitchenTable.usd new file mode 100755 index 0000000000..043b2eaf65 --- /dev/null +++ b/testsuite/test_0016/data/assets/KitchenTable/KitchenTable.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "KitchenTable" + upAxis = "Z" +) + +def Xform "KitchenTable" ( + assetInfo = { + asset identifier = @./assets/KitchenTable/KitchenTable.usd@ + string name = "KitchenTable" + } + kind = "component" + payload = @./KitchenTable_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/KitchenTable/KitchenTable_payload.usd b/testsuite/test_0016/data/assets/KitchenTable/KitchenTable_payload.usd new file mode 100755 index 0000000000..5f6c403fe0 --- /dev/null +++ b/testsuite/test_0016/data/assets/KitchenTable/KitchenTable_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "KitchenTable" + upAxis = "Z" +) + +def "KitchenTable" ( + assetInfo = { + asset identifier = @./assets/KitchenTable/KitchenTable.usd@ + string name = "KitchenTable" + } + add references = @./KitchenTable.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Knife/Knife.geom.usd b/testsuite/test_0016/data/assets/Knife/Knife.geom.usd new file mode 100755 index 0000000000..87ed5fa088 Binary files /dev/null and b/testsuite/test_0016/data/assets/Knife/Knife.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Knife/Knife.usd b/testsuite/test_0016/data/assets/Knife/Knife.usd new file mode 100755 index 0000000000..8a8d764680 --- /dev/null +++ b/testsuite/test_0016/data/assets/Knife/Knife.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "Knife" + upAxis = "Z" +) + +def Xform "Knife" ( + assetInfo = { + asset identifier = @./assets/Knife/Knife.usd@ + string name = "Knife" + } + kind = "component" + payload = @./Knife_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Knife/Knife_payload.usd b/testsuite/test_0016/data/assets/Knife/Knife_payload.usd new file mode 100755 index 0000000000..a05f2b8a1a --- /dev/null +++ b/testsuite/test_0016/data/assets/Knife/Knife_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Knife" + upAxis = "Z" +) + +def "Knife" ( + assetInfo = { + asset identifier = @./assets/Knife/Knife.usd@ + string name = "Knife" + } + add references = @./Knife.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/MeasuringCup/MeasuringCup.geom.usd b/testsuite/test_0016/data/assets/MeasuringCup/MeasuringCup.geom.usd new file mode 100755 index 0000000000..4c7d607f43 Binary files /dev/null and b/testsuite/test_0016/data/assets/MeasuringCup/MeasuringCup.geom.usd differ diff --git a/testsuite/test_0016/data/assets/MeasuringCup/MeasuringCup.usd b/testsuite/test_0016/data/assets/MeasuringCup/MeasuringCup.usd new file mode 100755 index 0000000000..ee1d93a32d --- /dev/null +++ b/testsuite/test_0016/data/assets/MeasuringCup/MeasuringCup.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "MeasuringCup" + upAxis = "Z" +) + +def Xform "MeasuringCup" ( + assetInfo = { + asset identifier = @./assets/MeasuringCup/MeasuringCup.usd@ + string name = "MeasuringCup" + } + kind = "component" + payload = @./MeasuringCup_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/MeasuringCup/MeasuringCup_payload.usd b/testsuite/test_0016/data/assets/MeasuringCup/MeasuringCup_payload.usd new file mode 100755 index 0000000000..315fa8193f --- /dev/null +++ b/testsuite/test_0016/data/assets/MeasuringCup/MeasuringCup_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "MeasuringCup" + upAxis = "Z" +) + +def "MeasuringCup" ( + assetInfo = { + asset identifier = @./assets/MeasuringCup/MeasuringCup.usd@ + string name = "MeasuringCup" + } + add references = @./MeasuringCup.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/MeasuringSpoon/MeasuringSpoon.geom.usd b/testsuite/test_0016/data/assets/MeasuringSpoon/MeasuringSpoon.geom.usd new file mode 100755 index 0000000000..15dd3c0244 Binary files /dev/null and b/testsuite/test_0016/data/assets/MeasuringSpoon/MeasuringSpoon.geom.usd differ diff --git a/testsuite/test_0016/data/assets/MeasuringSpoon/MeasuringSpoon.usd b/testsuite/test_0016/data/assets/MeasuringSpoon/MeasuringSpoon.usd new file mode 100755 index 0000000000..be4bc05800 --- /dev/null +++ b/testsuite/test_0016/data/assets/MeasuringSpoon/MeasuringSpoon.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "MeasuringSpoon" + upAxis = "Z" +) + +def Xform "MeasuringSpoon" ( + assetInfo = { + asset identifier = @./assets/MeasuringSpoon/MeasuringSpoon.usd@ + string name = "MeasuringSpoon" + } + kind = "component" + payload = @./MeasuringSpoon_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/MeasuringSpoon/MeasuringSpoon_payload.usd b/testsuite/test_0016/data/assets/MeasuringSpoon/MeasuringSpoon_payload.usd new file mode 100755 index 0000000000..a2eca0476d --- /dev/null +++ b/testsuite/test_0016/data/assets/MeasuringSpoon/MeasuringSpoon_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "MeasuringSpoon" + upAxis = "Z" +) + +def "MeasuringSpoon" ( + assetInfo = { + asset identifier = @./assets/MeasuringSpoon/MeasuringSpoon.usd@ + string name = "MeasuringSpoon" + } + add references = @./MeasuringSpoon.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Mixer/Mixer.geom.usd b/testsuite/test_0016/data/assets/Mixer/Mixer.geom.usd new file mode 100755 index 0000000000..3d993a6b33 Binary files /dev/null and b/testsuite/test_0016/data/assets/Mixer/Mixer.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Mixer/Mixer.usd b/testsuite/test_0016/data/assets/Mixer/Mixer.usd new file mode 100755 index 0000000000..a21f9658d1 --- /dev/null +++ b/testsuite/test_0016/data/assets/Mixer/Mixer.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "Mixer" + upAxis = "Z" +) + +def Xform "Mixer" ( + assetInfo = { + asset identifier = @./assets/Mixer/Mixer.usd@ + string name = "Mixer" + } + kind = "component" + payload = @./Mixer_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Mixer/Mixer_payload.usd b/testsuite/test_0016/data/assets/Mixer/Mixer_payload.usd new file mode 100755 index 0000000000..6ba01db8b1 --- /dev/null +++ b/testsuite/test_0016/data/assets/Mixer/Mixer_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Mixer" + upAxis = "Z" +) + +def "Mixer" ( + assetInfo = { + asset identifier = @./assets/Mixer/Mixer.usd@ + string name = "Mixer" + } + add references = @./Mixer.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Nail/Nail.geom.usd b/testsuite/test_0016/data/assets/Nail/Nail.geom.usd new file mode 100755 index 0000000000..046c2607e7 Binary files /dev/null and b/testsuite/test_0016/data/assets/Nail/Nail.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Nail/Nail.usd b/testsuite/test_0016/data/assets/Nail/Nail.usd new file mode 100755 index 0000000000..65e093ccc3 --- /dev/null +++ b/testsuite/test_0016/data/assets/Nail/Nail.usd @@ -0,0 +1,30 @@ +#usda 1.0 +( + defaultPrim = "Nail" + upAxis = "Z" +) + +def Xform "Nail" ( + assetInfo = { + asset identifier = @./assets/Nail/Nail.usd@ + string name = "Nail" + } + kind = "component" + payload = @./Nail_payload.usd@ + variants = { + string modelingVariant = "NailA" + } + add variantSets = ["modelingVariant"] +) +{ + variantSet "modelingVariant" = { + "NailA" { + + } + "NailB" { + + } + } +} + + diff --git a/testsuite/test_0016/data/assets/Nail/Nail_payload.usd b/testsuite/test_0016/data/assets/Nail/Nail_payload.usd new file mode 100755 index 0000000000..3db266c318 --- /dev/null +++ b/testsuite/test_0016/data/assets/Nail/Nail_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Nail" + upAxis = "Z" +) + +def "Nail" ( + assetInfo = { + asset identifier = @./assets/Nail/Nail.usd@ + string name = "Nail" + } + add references = @./Nail.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/OilBottle/OilBottle.geom.usd b/testsuite/test_0016/data/assets/OilBottle/OilBottle.geom.usd new file mode 100755 index 0000000000..67e8bc09fb Binary files /dev/null and b/testsuite/test_0016/data/assets/OilBottle/OilBottle.geom.usd differ diff --git a/testsuite/test_0016/data/assets/OilBottle/OilBottle.usd b/testsuite/test_0016/data/assets/OilBottle/OilBottle.usd new file mode 100755 index 0000000000..c8cb9b08b7 --- /dev/null +++ b/testsuite/test_0016/data/assets/OilBottle/OilBottle.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "OilBottle" + upAxis = "Z" +) + +def Xform "OilBottle" ( + assetInfo = { + asset identifier = @./assets/OilBottle/OilBottle.usd@ + string name = "OilBottle" + } + kind = "component" + payload = @./OilBottle_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/OilBottle/OilBottle_payload.usd b/testsuite/test_0016/data/assets/OilBottle/OilBottle_payload.usd new file mode 100755 index 0000000000..aa97914c88 --- /dev/null +++ b/testsuite/test_0016/data/assets/OilBottle/OilBottle_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "OilBottle" + upAxis = "Z" +) + +def "OilBottle" ( + assetInfo = { + asset identifier = @./assets/OilBottle/OilBottle.usd@ + string name = "OilBottle" + } + add references = @./OilBottle.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Pan/Pan.geom.usd b/testsuite/test_0016/data/assets/Pan/Pan.geom.usd new file mode 100755 index 0000000000..cc31d22725 Binary files /dev/null and b/testsuite/test_0016/data/assets/Pan/Pan.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Pan/Pan.usd b/testsuite/test_0016/data/assets/Pan/Pan.usd new file mode 100755 index 0000000000..3bbc72fc8d --- /dev/null +++ b/testsuite/test_0016/data/assets/Pan/Pan.usd @@ -0,0 +1,30 @@ +#usda 1.0 +( + defaultPrim = "Pan" + upAxis = "Z" +) + +def Xform "Pan" ( + assetInfo = { + asset identifier = @./assets/Pan/Pan.usd@ + string name = "Pan" + } + kind = "component" + payload = @./Pan_payload.usd@ + variants = { + string modelingVariant = "PanA" + } + add variantSets = ["modelingVariant"] +) +{ + variantSet "modelingVariant" = { + "PanA" { + + } + "PanB" { + + } + } +} + + diff --git a/testsuite/test_0016/data/assets/Pan/Pan_payload.usd b/testsuite/test_0016/data/assets/Pan/Pan_payload.usd new file mode 100755 index 0000000000..96ea019809 --- /dev/null +++ b/testsuite/test_0016/data/assets/Pan/Pan_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Pan" + upAxis = "Z" +) + +def "Pan" ( + assetInfo = { + asset identifier = @./assets/Pan/Pan.usd@ + string name = "Pan" + } + add references = @./Pan.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/PaperBagCrumpled/PaperBagCrumpled.geom.usd b/testsuite/test_0016/data/assets/PaperBagCrumpled/PaperBagCrumpled.geom.usd new file mode 100755 index 0000000000..529e12a936 Binary files /dev/null and b/testsuite/test_0016/data/assets/PaperBagCrumpled/PaperBagCrumpled.geom.usd differ diff --git a/testsuite/test_0016/data/assets/PaperBagCrumpled/PaperBagCrumpled.usd b/testsuite/test_0016/data/assets/PaperBagCrumpled/PaperBagCrumpled.usd new file mode 100755 index 0000000000..6d2e736a59 --- /dev/null +++ b/testsuite/test_0016/data/assets/PaperBagCrumpled/PaperBagCrumpled.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "PaperBagCrumpled" + upAxis = "Z" +) + +def Xform "PaperBagCrumpled" ( + assetInfo = { + asset identifier = @./assets/PaperBagCrumpled/PaperBagCrumpled.usd@ + string name = "PaperBagCrumpled" + } + kind = "component" + payload = @./PaperBagCrumpled_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/PaperBagCrumpled/PaperBagCrumpled_payload.usd b/testsuite/test_0016/data/assets/PaperBagCrumpled/PaperBagCrumpled_payload.usd new file mode 100755 index 0000000000..73f7c63b03 --- /dev/null +++ b/testsuite/test_0016/data/assets/PaperBagCrumpled/PaperBagCrumpled_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "PaperBagCrumpled" + upAxis = "Z" +) + +def "PaperBagCrumpled" ( + assetInfo = { + asset identifier = @./assets/PaperBagCrumpled/PaperBagCrumpled.usd@ + string name = "PaperBagCrumpled" + } + add references = @./PaperBagCrumpled.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/PaperLarge/PaperLarge.geom.usd b/testsuite/test_0016/data/assets/PaperLarge/PaperLarge.geom.usd new file mode 100755 index 0000000000..59ffcfdd93 Binary files /dev/null and b/testsuite/test_0016/data/assets/PaperLarge/PaperLarge.geom.usd differ diff --git a/testsuite/test_0016/data/assets/PaperLarge/PaperLarge.usd b/testsuite/test_0016/data/assets/PaperLarge/PaperLarge.usd new file mode 100755 index 0000000000..d17d6e452b --- /dev/null +++ b/testsuite/test_0016/data/assets/PaperLarge/PaperLarge.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "PaperLarge" + upAxis = "Z" +) + +def Xform "PaperLarge" ( + assetInfo = { + asset identifier = @./assets/PaperLarge/PaperLarge.usd@ + string name = "PaperLarge" + } + kind = "component" + payload = @./PaperLarge_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/PaperLarge/PaperLarge_payload.usd b/testsuite/test_0016/data/assets/PaperLarge/PaperLarge_payload.usd new file mode 100755 index 0000000000..875199c6fb --- /dev/null +++ b/testsuite/test_0016/data/assets/PaperLarge/PaperLarge_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "PaperLarge" + upAxis = "Z" +) + +def "PaperLarge" ( + assetInfo = { + asset identifier = @./assets/PaperLarge/PaperLarge.usd@ + string name = "PaperLarge" + } + add references = @./PaperLarge.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/PaperSmall/PaperSmall.geom.usd b/testsuite/test_0016/data/assets/PaperSmall/PaperSmall.geom.usd new file mode 100755 index 0000000000..26bea17944 Binary files /dev/null and b/testsuite/test_0016/data/assets/PaperSmall/PaperSmall.geom.usd differ diff --git a/testsuite/test_0016/data/assets/PaperSmall/PaperSmall.usd b/testsuite/test_0016/data/assets/PaperSmall/PaperSmall.usd new file mode 100755 index 0000000000..ba3d2ef58e --- /dev/null +++ b/testsuite/test_0016/data/assets/PaperSmall/PaperSmall.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "PaperSmall" + upAxis = "Z" +) + +def Xform "PaperSmall" ( + assetInfo = { + asset identifier = @./assets/PaperSmall/PaperSmall.usd@ + string name = "PaperSmall" + } + kind = "component" + payload = @./PaperSmall_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/PaperSmall/PaperSmall_payload.usd b/testsuite/test_0016/data/assets/PaperSmall/PaperSmall_payload.usd new file mode 100755 index 0000000000..2573885102 --- /dev/null +++ b/testsuite/test_0016/data/assets/PaperSmall/PaperSmall_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "PaperSmall" + upAxis = "Z" +) + +def "PaperSmall" ( + assetInfo = { + asset identifier = @./assets/PaperSmall/PaperSmall.usd@ + string name = "PaperSmall" + } + add references = @./PaperSmall.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/PaperTowelRoll/PaperTowelRoll.geom.usd b/testsuite/test_0016/data/assets/PaperTowelRoll/PaperTowelRoll.geom.usd new file mode 100755 index 0000000000..164a21c5f7 Binary files /dev/null and b/testsuite/test_0016/data/assets/PaperTowelRoll/PaperTowelRoll.geom.usd differ diff --git a/testsuite/test_0016/data/assets/PaperTowelRoll/PaperTowelRoll.usd b/testsuite/test_0016/data/assets/PaperTowelRoll/PaperTowelRoll.usd new file mode 100755 index 0000000000..e31959d0c2 --- /dev/null +++ b/testsuite/test_0016/data/assets/PaperTowelRoll/PaperTowelRoll.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "PaperTowelRoll" + upAxis = "Z" +) + +def Xform "PaperTowelRoll" ( + assetInfo = { + asset identifier = @./assets/PaperTowelRoll/PaperTowelRoll.usd@ + string name = "PaperTowelRoll" + } + kind = "component" + payload = @./PaperTowelRoll_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/PaperTowelRoll/PaperTowelRoll_payload.usd b/testsuite/test_0016/data/assets/PaperTowelRoll/PaperTowelRoll_payload.usd new file mode 100755 index 0000000000..277cb8d03e --- /dev/null +++ b/testsuite/test_0016/data/assets/PaperTowelRoll/PaperTowelRoll_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "PaperTowelRoll" + upAxis = "Z" +) + +def "PaperTowelRoll" ( + assetInfo = { + asset identifier = @./assets/PaperTowelRoll/PaperTowelRoll.usd@ + string name = "PaperTowelRoll" + } + add references = @./PaperTowelRoll.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/PaperWrinkle/PaperWrinkle.geom.usd b/testsuite/test_0016/data/assets/PaperWrinkle/PaperWrinkle.geom.usd new file mode 100755 index 0000000000..5b65503b07 Binary files /dev/null and b/testsuite/test_0016/data/assets/PaperWrinkle/PaperWrinkle.geom.usd differ diff --git a/testsuite/test_0016/data/assets/PaperWrinkle/PaperWrinkle.usd b/testsuite/test_0016/data/assets/PaperWrinkle/PaperWrinkle.usd new file mode 100755 index 0000000000..1b87ba0b3c --- /dev/null +++ b/testsuite/test_0016/data/assets/PaperWrinkle/PaperWrinkle.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "PaperWrinkle" + upAxis = "Z" +) + +def Xform "PaperWrinkle" ( + assetInfo = { + asset identifier = @./assets/PaperWrinkle/PaperWrinkle.usd@ + string name = "PaperWrinkle" + } + kind = "component" + payload = @./PaperWrinkle_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/PaperWrinkle/PaperWrinkle_payload.usd b/testsuite/test_0016/data/assets/PaperWrinkle/PaperWrinkle_payload.usd new file mode 100755 index 0000000000..1d7f269a7d --- /dev/null +++ b/testsuite/test_0016/data/assets/PaperWrinkle/PaperWrinkle_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "PaperWrinkle" + upAxis = "Z" +) + +def "PaperWrinkle" ( + assetInfo = { + asset identifier = @./assets/PaperWrinkle/PaperWrinkle.usd@ + string name = "PaperWrinkle" + } + add references = @./PaperWrinkle.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Plate/Plate.geom.usd b/testsuite/test_0016/data/assets/Plate/Plate.geom.usd new file mode 100755 index 0000000000..7b3535c8e5 Binary files /dev/null and b/testsuite/test_0016/data/assets/Plate/Plate.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Plate/Plate.usd b/testsuite/test_0016/data/assets/Plate/Plate.usd new file mode 100755 index 0000000000..b384db28b3 --- /dev/null +++ b/testsuite/test_0016/data/assets/Plate/Plate.usd @@ -0,0 +1,42 @@ +#usda 1.0 +( + defaultPrim = "Plate" + upAxis = "Z" +) + +def Xform "Plate" ( + assetInfo = { + asset identifier = @./assets/Plate/Plate.usd@ + string name = "Plate" + } + kind = "component" + payload = @./Plate_payload.usd@ + variants = { + string modelingVariant = "PlateA" + string shadingVariant = "Default" + } + add variantSets = ["shadingVariant", "modelingVariant"] +) +{ + variantSet "shadingVariant" = { + "Clean" { + + } + "Default" { + + } + "Dirty" { + + } + } + variantSet "modelingVariant" = { + "PlateA" { + + } + "PlateB" { + + } + } +} + + diff --git a/testsuite/test_0016/data/assets/Plate/Plate_payload.usd b/testsuite/test_0016/data/assets/Plate/Plate_payload.usd new file mode 100755 index 0000000000..9b696ef6ec --- /dev/null +++ b/testsuite/test_0016/data/assets/Plate/Plate_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Plate" + upAxis = "Z" +) + +def "Plate" ( + assetInfo = { + asset identifier = @./assets/Plate/Plate.usd@ + string name = "Plate" + } + add references = @./Plate.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Pot/Pot.geom.usd b/testsuite/test_0016/data/assets/Pot/Pot.geom.usd new file mode 100755 index 0000000000..ef4453f426 Binary files /dev/null and b/testsuite/test_0016/data/assets/Pot/Pot.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Pot/Pot.usd b/testsuite/test_0016/data/assets/Pot/Pot.usd new file mode 100755 index 0000000000..b497b8d9da --- /dev/null +++ b/testsuite/test_0016/data/assets/Pot/Pot.usd @@ -0,0 +1,42 @@ +#usda 1.0 +( + defaultPrim = "Pot" + upAxis = "Z" +) + +def Xform "Pot" ( + assetInfo = { + asset identifier = @./assets/Pot/Pot.usd@ + string name = "Pot" + } + kind = "component" + payload = @./Pot_payload.usd@ + variants = { + string modelingVariant = "PotA" + string shadingVariant = "Default" + } + add variantSets = ["shadingVariant", "modelingVariant"] +) +{ + variantSet "shadingVariant" = { + "Dark" { + + } + "Default" { + + } + "Light" { + + } + } + variantSet "modelingVariant" = { + "PotA" { + + } + "PotB" { + + } + } +} + + diff --git a/testsuite/test_0016/data/assets/Pot/Pot_payload.usd b/testsuite/test_0016/data/assets/Pot/Pot_payload.usd new file mode 100755 index 0000000000..569a237870 --- /dev/null +++ b/testsuite/test_0016/data/assets/Pot/Pot_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Pot" + upAxis = "Z" +) + +def "Pot" ( + assetInfo = { + asset identifier = @./assets/Pot/Pot.usd@ + string name = "Pot" + } + add references = @./Pot.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Refridgerator/Refridgerator.geom.usd b/testsuite/test_0016/data/assets/Refridgerator/Refridgerator.geom.usd new file mode 100755 index 0000000000..58cdfa608d Binary files /dev/null and b/testsuite/test_0016/data/assets/Refridgerator/Refridgerator.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Refridgerator/Refridgerator.usd b/testsuite/test_0016/data/assets/Refridgerator/Refridgerator.usd new file mode 100755 index 0000000000..ae57f27a90 --- /dev/null +++ b/testsuite/test_0016/data/assets/Refridgerator/Refridgerator.usd @@ -0,0 +1,30 @@ +#usda 1.0 +( + defaultPrim = "Refridgerator" + upAxis = "Z" +) + +def Xform "Refridgerator" ( + assetInfo = { + asset identifier = @./assets/Refridgerator/Refridgerator.usd@ + string name = "Refridgerator" + } + kind = "component" + payload = @./Refridgerator_payload.usd@ + variants = { + string modelingVariant = "Decorated" + } + add variantSets = ["modelingVariant"] +) +{ + variantSet "modelingVariant" = { + "Bare" { + + } + "Decorated" { + + } + } +} + + diff --git a/testsuite/test_0016/data/assets/Refridgerator/Refridgerator_payload.usd b/testsuite/test_0016/data/assets/Refridgerator/Refridgerator_payload.usd new file mode 100755 index 0000000000..ca0ad9077a --- /dev/null +++ b/testsuite/test_0016/data/assets/Refridgerator/Refridgerator_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Refridgerator" + upAxis = "Z" +) + +def "Refridgerator" ( + assetInfo = { + asset identifier = @./assets/Refridgerator/Refridgerator.usd@ + string name = "Refridgerator" + } + add references = @./Refridgerator.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/RollingPin/RollingPin.geom.usd b/testsuite/test_0016/data/assets/RollingPin/RollingPin.geom.usd new file mode 100755 index 0000000000..5b753726f0 Binary files /dev/null and b/testsuite/test_0016/data/assets/RollingPin/RollingPin.geom.usd differ diff --git a/testsuite/test_0016/data/assets/RollingPin/RollingPin.usd b/testsuite/test_0016/data/assets/RollingPin/RollingPin.usd new file mode 100755 index 0000000000..b3cd0ead7a --- /dev/null +++ b/testsuite/test_0016/data/assets/RollingPin/RollingPin.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "RollingPin" + upAxis = "Z" +) + +def Xform "RollingPin" ( + assetInfo = { + asset identifier = @./assets/RollingPin/RollingPin.usd@ + string name = "RollingPin" + } + kind = "component" + payload = @./RollingPin_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/RollingPin/RollingPin_payload.usd b/testsuite/test_0016/data/assets/RollingPin/RollingPin_payload.usd new file mode 100755 index 0000000000..fa5423235d --- /dev/null +++ b/testsuite/test_0016/data/assets/RollingPin/RollingPin_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "RollingPin" + upAxis = "Z" +) + +def "RollingPin" ( + assetInfo = { + asset identifier = @./assets/RollingPin/RollingPin.usd@ + string name = "RollingPin" + } + add references = @./RollingPin.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Rug/Rug.geom.usd b/testsuite/test_0016/data/assets/Rug/Rug.geom.usd new file mode 100755 index 0000000000..c0eb223af3 Binary files /dev/null and b/testsuite/test_0016/data/assets/Rug/Rug.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Rug/Rug.usd b/testsuite/test_0016/data/assets/Rug/Rug.usd new file mode 100755 index 0000000000..9a48aef80c --- /dev/null +++ b/testsuite/test_0016/data/assets/Rug/Rug.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "Rug" + upAxis = "Z" +) + +def Xform "Rug" ( + assetInfo = { + asset identifier = @./assets/Rug/Rug.usd@ + string name = "Rug" + } + kind = "component" + payload = @./Rug_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Rug/Rug_payload.usd b/testsuite/test_0016/data/assets/Rug/Rug_payload.usd new file mode 100755 index 0000000000..baab6c54c2 --- /dev/null +++ b/testsuite/test_0016/data/assets/Rug/Rug_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Rug" + upAxis = "Z" +) + +def "Rug" ( + assetInfo = { + asset identifier = @./assets/Rug/Rug.usd@ + string name = "Rug" + } + add references = @./Rug.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/SaltShaker/SaltShaker.geom.usd b/testsuite/test_0016/data/assets/SaltShaker/SaltShaker.geom.usd new file mode 100755 index 0000000000..11d75dce6f Binary files /dev/null and b/testsuite/test_0016/data/assets/SaltShaker/SaltShaker.geom.usd differ diff --git a/testsuite/test_0016/data/assets/SaltShaker/SaltShaker.usd b/testsuite/test_0016/data/assets/SaltShaker/SaltShaker.usd new file mode 100755 index 0000000000..e50b81db9e --- /dev/null +++ b/testsuite/test_0016/data/assets/SaltShaker/SaltShaker.usd @@ -0,0 +1,33 @@ +#usda 1.0 +( + defaultPrim = "SaltShaker" + upAxis = "Z" +) + +def Xform "SaltShaker" ( + assetInfo = { + asset identifier = @./assets/SaltShaker/SaltShaker.usd@ + string name = "SaltShaker" + } + kind = "component" + payload = @./SaltShaker_payload.usd@ + variants = { + string shadingVariant = "Default" + } + add variantSets = ["shadingVariant"] +) +{ + variantSet "shadingVariant" = { + "Default" { + + } + "ShakerPepper" { + + } + "ShakerSalt" { + + } + } +} + + diff --git a/testsuite/test_0016/data/assets/SaltShaker/SaltShaker_payload.usd b/testsuite/test_0016/data/assets/SaltShaker/SaltShaker_payload.usd new file mode 100755 index 0000000000..fec0537b2a --- /dev/null +++ b/testsuite/test_0016/data/assets/SaltShaker/SaltShaker_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "SaltShaker" + upAxis = "Z" +) + +def "SaltShaker" ( + assetInfo = { + asset identifier = @./assets/SaltShaker/SaltShaker.usd@ + string name = "SaltShaker" + } + add references = @./SaltShaker.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/ShellLarge/ShellLarge.geom.usd b/testsuite/test_0016/data/assets/ShellLarge/ShellLarge.geom.usd new file mode 100755 index 0000000000..93e5b1fc29 Binary files /dev/null and b/testsuite/test_0016/data/assets/ShellLarge/ShellLarge.geom.usd differ diff --git a/testsuite/test_0016/data/assets/ShellLarge/ShellLarge.usd b/testsuite/test_0016/data/assets/ShellLarge/ShellLarge.usd new file mode 100755 index 0000000000..55bc28be9b --- /dev/null +++ b/testsuite/test_0016/data/assets/ShellLarge/ShellLarge.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "ShellLarge" + upAxis = "Z" +) + +def Xform "ShellLarge" ( + assetInfo = { + asset identifier = @./assets/ShellLarge/ShellLarge.usd@ + string name = "ShellLarge" + } + kind = "component" + payload = @./ShellLarge_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/ShellLarge/ShellLarge_payload.usd b/testsuite/test_0016/data/assets/ShellLarge/ShellLarge_payload.usd new file mode 100755 index 0000000000..bfb0505bc9 --- /dev/null +++ b/testsuite/test_0016/data/assets/ShellLarge/ShellLarge_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "ShellLarge" + upAxis = "Z" +) + +def "ShellLarge" ( + assetInfo = { + asset identifier = @./assets/ShellLarge/ShellLarge.usd@ + string name = "ShellLarge" + } + add references = @./ShellLarge.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/ShellSmall/ShellSmall.geom.usd b/testsuite/test_0016/data/assets/ShellSmall/ShellSmall.geom.usd new file mode 100755 index 0000000000..138e6a946a Binary files /dev/null and b/testsuite/test_0016/data/assets/ShellSmall/ShellSmall.geom.usd differ diff --git a/testsuite/test_0016/data/assets/ShellSmall/ShellSmall.usd b/testsuite/test_0016/data/assets/ShellSmall/ShellSmall.usd new file mode 100755 index 0000000000..95ad72b4c0 --- /dev/null +++ b/testsuite/test_0016/data/assets/ShellSmall/ShellSmall.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "ShellSmall" + upAxis = "Z" +) + +def Xform "ShellSmall" ( + assetInfo = { + asset identifier = @./assets/ShellSmall/ShellSmall.usd@ + string name = "ShellSmall" + } + kind = "component" + payload = @./ShellSmall_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/ShellSmall/ShellSmall_payload.usd b/testsuite/test_0016/data/assets/ShellSmall/ShellSmall_payload.usd new file mode 100755 index 0000000000..450a7e31ae --- /dev/null +++ b/testsuite/test_0016/data/assets/ShellSmall/ShellSmall_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "ShellSmall" + upAxis = "Z" +) + +def "ShellSmall" ( + assetInfo = { + asset identifier = @./assets/ShellSmall/ShellSmall.usd@ + string name = "ShellSmall" + } + add references = @./ShellSmall.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/SoapDish/SoapDish.geom.usd b/testsuite/test_0016/data/assets/SoapDish/SoapDish.geom.usd new file mode 100755 index 0000000000..4359b468d8 Binary files /dev/null and b/testsuite/test_0016/data/assets/SoapDish/SoapDish.geom.usd differ diff --git a/testsuite/test_0016/data/assets/SoapDish/SoapDish.usd b/testsuite/test_0016/data/assets/SoapDish/SoapDish.usd new file mode 100755 index 0000000000..d8f063383b --- /dev/null +++ b/testsuite/test_0016/data/assets/SoapDish/SoapDish.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "SoapDish" + upAxis = "Z" +) + +def Xform "SoapDish" ( + assetInfo = { + asset identifier = @./assets/SoapDish/SoapDish.usd@ + string name = "SoapDish" + } + kind = "component" + payload = @./SoapDish_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/SoapDish/SoapDish_payload.usd b/testsuite/test_0016/data/assets/SoapDish/SoapDish_payload.usd new file mode 100755 index 0000000000..92f4a0adaf --- /dev/null +++ b/testsuite/test_0016/data/assets/SoapDish/SoapDish_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "SoapDish" + upAxis = "Z" +) + +def "SoapDish" ( + assetInfo = { + asset identifier = @./assets/SoapDish/SoapDish.usd@ + string name = "SoapDish" + } + add references = @./SoapDish.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/SoapDispenser/SoapDispenser.geom.usd b/testsuite/test_0016/data/assets/SoapDispenser/SoapDispenser.geom.usd new file mode 100755 index 0000000000..3ec53b92a4 Binary files /dev/null and b/testsuite/test_0016/data/assets/SoapDispenser/SoapDispenser.geom.usd differ diff --git a/testsuite/test_0016/data/assets/SoapDispenser/SoapDispenser.usd b/testsuite/test_0016/data/assets/SoapDispenser/SoapDispenser.usd new file mode 100755 index 0000000000..7f24311270 --- /dev/null +++ b/testsuite/test_0016/data/assets/SoapDispenser/SoapDispenser.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "SoapDispenser" + upAxis = "Z" +) + +def Xform "SoapDispenser" ( + assetInfo = { + asset identifier = @./assets/SoapDispenser/SoapDispenser.usd@ + string name = "SoapDispenser" + } + kind = "component" + payload = @./SoapDispenser_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/SoapDispenser/SoapDispenser_payload.usd b/testsuite/test_0016/data/assets/SoapDispenser/SoapDispenser_payload.usd new file mode 100755 index 0000000000..17df85fd40 --- /dev/null +++ b/testsuite/test_0016/data/assets/SoapDispenser/SoapDispenser_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "SoapDispenser" + upAxis = "Z" +) + +def "SoapDispenser" ( + assetInfo = { + asset identifier = @./assets/SoapDispenser/SoapDispenser.usd@ + string name = "SoapDispenser" + } + add references = @./SoapDispenser.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/SoapSponge/SoapSponge.geom.usd b/testsuite/test_0016/data/assets/SoapSponge/SoapSponge.geom.usd new file mode 100755 index 0000000000..0f27642e28 Binary files /dev/null and b/testsuite/test_0016/data/assets/SoapSponge/SoapSponge.geom.usd differ diff --git a/testsuite/test_0016/data/assets/SoapSponge/SoapSponge.usd b/testsuite/test_0016/data/assets/SoapSponge/SoapSponge.usd new file mode 100755 index 0000000000..f467479edc --- /dev/null +++ b/testsuite/test_0016/data/assets/SoapSponge/SoapSponge.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "SoapSponge" + upAxis = "Z" +) + +def Xform "SoapSponge" ( + assetInfo = { + asset identifier = @./assets/SoapSponge/SoapSponge.usd@ + string name = "SoapSponge" + } + kind = "component" + payload = @./SoapSponge_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/SoapSponge/SoapSponge_payload.usd b/testsuite/test_0016/data/assets/SoapSponge/SoapSponge_payload.usd new file mode 100755 index 0000000000..9f8b4083e5 --- /dev/null +++ b/testsuite/test_0016/data/assets/SoapSponge/SoapSponge_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "SoapSponge" + upAxis = "Z" +) + +def "SoapSponge" ( + assetInfo = { + asset identifier = @./assets/SoapSponge/SoapSponge.usd@ + string name = "SoapSponge" + } + add references = @./SoapSponge.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Spatula/Spatula.geom.usd b/testsuite/test_0016/data/assets/Spatula/Spatula.geom.usd new file mode 100755 index 0000000000..97c8fa4029 Binary files /dev/null and b/testsuite/test_0016/data/assets/Spatula/Spatula.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Spatula/Spatula.usd b/testsuite/test_0016/data/assets/Spatula/Spatula.usd new file mode 100755 index 0000000000..163f3d12a7 --- /dev/null +++ b/testsuite/test_0016/data/assets/Spatula/Spatula.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "Spatula" + upAxis = "Z" +) + +def Xform "Spatula" ( + assetInfo = { + asset identifier = @./assets/Spatula/Spatula.usd@ + string name = "Spatula" + } + kind = "component" + payload = @./Spatula_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Spatula/Spatula_payload.usd b/testsuite/test_0016/data/assets/Spatula/Spatula_payload.usd new file mode 100755 index 0000000000..a7344c307f --- /dev/null +++ b/testsuite/test_0016/data/assets/Spatula/Spatula_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Spatula" + upAxis = "Z" +) + +def "Spatula" ( + assetInfo = { + asset identifier = @./assets/Spatula/Spatula.usd@ + string name = "Spatula" + } + add references = @./Spatula.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/SpatulaSlotted/SpatulaSlotted.geom.usd b/testsuite/test_0016/data/assets/SpatulaSlotted/SpatulaSlotted.geom.usd new file mode 100755 index 0000000000..70d1d4e096 Binary files /dev/null and b/testsuite/test_0016/data/assets/SpatulaSlotted/SpatulaSlotted.geom.usd differ diff --git a/testsuite/test_0016/data/assets/SpatulaSlotted/SpatulaSlotted.usd b/testsuite/test_0016/data/assets/SpatulaSlotted/SpatulaSlotted.usd new file mode 100755 index 0000000000..80848cca76 --- /dev/null +++ b/testsuite/test_0016/data/assets/SpatulaSlotted/SpatulaSlotted.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "SpatulaSlotted" + upAxis = "Z" +) + +def Xform "SpatulaSlotted" ( + assetInfo = { + asset identifier = @./assets/SpatulaSlotted/SpatulaSlotted.usd@ + string name = "SpatulaSlotted" + } + kind = "component" + payload = @./SpatulaSlotted_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/SpatulaSlotted/SpatulaSlotted_payload.usd b/testsuite/test_0016/data/assets/SpatulaSlotted/SpatulaSlotted_payload.usd new file mode 100755 index 0000000000..e176831f8f --- /dev/null +++ b/testsuite/test_0016/data/assets/SpatulaSlotted/SpatulaSlotted_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "SpatulaSlotted" + upAxis = "Z" +) + +def "SpatulaSlotted" ( + assetInfo = { + asset identifier = @./assets/SpatulaSlotted/SpatulaSlotted.usd@ + string name = "SpatulaSlotted" + } + add references = @./SpatulaSlotted.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/SpiceBox/SpiceBox.geom.usd b/testsuite/test_0016/data/assets/SpiceBox/SpiceBox.geom.usd new file mode 100755 index 0000000000..a4b4f14fca Binary files /dev/null and b/testsuite/test_0016/data/assets/SpiceBox/SpiceBox.geom.usd differ diff --git a/testsuite/test_0016/data/assets/SpiceBox/SpiceBox.usd b/testsuite/test_0016/data/assets/SpiceBox/SpiceBox.usd new file mode 100755 index 0000000000..c469f78877 --- /dev/null +++ b/testsuite/test_0016/data/assets/SpiceBox/SpiceBox.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "SpiceBox" + upAxis = "Z" +) + +def Xform "SpiceBox" ( + assetInfo = { + asset identifier = @./assets/SpiceBox/SpiceBox.usd@ + string name = "SpiceBox" + } + kind = "component" + payload = @./SpiceBox_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/SpiceBox/SpiceBox_payload.usd b/testsuite/test_0016/data/assets/SpiceBox/SpiceBox_payload.usd new file mode 100755 index 0000000000..e7a046179f --- /dev/null +++ b/testsuite/test_0016/data/assets/SpiceBox/SpiceBox_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "SpiceBox" + upAxis = "Z" +) + +def "SpiceBox" ( + assetInfo = { + asset identifier = @./assets/SpiceBox/SpiceBox.usd@ + string name = "SpiceBox" + } + add references = @./SpiceBox.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/SpiceShaker/SpiceShaker.geom.usd b/testsuite/test_0016/data/assets/SpiceShaker/SpiceShaker.geom.usd new file mode 100755 index 0000000000..420340065d Binary files /dev/null and b/testsuite/test_0016/data/assets/SpiceShaker/SpiceShaker.geom.usd differ diff --git a/testsuite/test_0016/data/assets/SpiceShaker/SpiceShaker.usd b/testsuite/test_0016/data/assets/SpiceShaker/SpiceShaker.usd new file mode 100755 index 0000000000..a64f1042df --- /dev/null +++ b/testsuite/test_0016/data/assets/SpiceShaker/SpiceShaker.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "SpiceShaker" + upAxis = "Z" +) + +def Xform "SpiceShaker" ( + assetInfo = { + asset identifier = @./assets/SpiceShaker/SpiceShaker.usd@ + string name = "SpiceShaker" + } + kind = "component" + payload = @./SpiceShaker_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/SpiceShaker/SpiceShaker_payload.usd b/testsuite/test_0016/data/assets/SpiceShaker/SpiceShaker_payload.usd new file mode 100755 index 0000000000..48321c2398 --- /dev/null +++ b/testsuite/test_0016/data/assets/SpiceShaker/SpiceShaker_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "SpiceShaker" + upAxis = "Z" +) + +def "SpiceShaker" ( + assetInfo = { + asset identifier = @./assets/SpiceShaker/SpiceShaker.usd@ + string name = "SpiceShaker" + } + add references = @./SpiceShaker.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Spoon/Spoon.geom.usd b/testsuite/test_0016/data/assets/Spoon/Spoon.geom.usd new file mode 100755 index 0000000000..3a697662ec Binary files /dev/null and b/testsuite/test_0016/data/assets/Spoon/Spoon.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Spoon/Spoon.usd b/testsuite/test_0016/data/assets/Spoon/Spoon.usd new file mode 100755 index 0000000000..0b519edc7c --- /dev/null +++ b/testsuite/test_0016/data/assets/Spoon/Spoon.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "Spoon" + upAxis = "Z" +) + +def Xform "Spoon" ( + assetInfo = { + asset identifier = @./assets/Spoon/Spoon.usd@ + string name = "Spoon" + } + kind = "component" + payload = @./Spoon_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Spoon/Spoon_payload.usd b/testsuite/test_0016/data/assets/Spoon/Spoon_payload.usd new file mode 100755 index 0000000000..efa6069964 --- /dev/null +++ b/testsuite/test_0016/data/assets/Spoon/Spoon_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Spoon" + upAxis = "Z" +) + +def "Spoon" ( + assetInfo = { + asset identifier = @./assets/Spoon/Spoon.usd@ + string name = "Spoon" + } + add references = @./Spoon.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/SpoonSpaghetti/SpoonSpaghetti.geom.usd b/testsuite/test_0016/data/assets/SpoonSpaghetti/SpoonSpaghetti.geom.usd new file mode 100755 index 0000000000..db2389d21f Binary files /dev/null and b/testsuite/test_0016/data/assets/SpoonSpaghetti/SpoonSpaghetti.geom.usd differ diff --git a/testsuite/test_0016/data/assets/SpoonSpaghetti/SpoonSpaghetti.usd b/testsuite/test_0016/data/assets/SpoonSpaghetti/SpoonSpaghetti.usd new file mode 100755 index 0000000000..4ccc159f93 --- /dev/null +++ b/testsuite/test_0016/data/assets/SpoonSpaghetti/SpoonSpaghetti.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "SpoonSpaghetti" + upAxis = "Z" +) + +def Xform "SpoonSpaghetti" ( + assetInfo = { + asset identifier = @./assets/SpoonSpaghetti/SpoonSpaghetti.usd@ + string name = "SpoonSpaghetti" + } + kind = "component" + payload = @./SpoonSpaghetti_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/SpoonSpaghetti/SpoonSpaghetti_payload.usd b/testsuite/test_0016/data/assets/SpoonSpaghetti/SpoonSpaghetti_payload.usd new file mode 100755 index 0000000000..2a2f5f27e5 --- /dev/null +++ b/testsuite/test_0016/data/assets/SpoonSpaghetti/SpoonSpaghetti_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "SpoonSpaghetti" + upAxis = "Z" +) + +def "SpoonSpaghetti" ( + assetInfo = { + asset identifier = @./assets/SpoonSpaghetti/SpoonSpaghetti.usd@ + string name = "SpoonSpaghetti" + } + add references = @./SpoonSpaghetti.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/SteamCooker/SteamCooker.geom.usd b/testsuite/test_0016/data/assets/SteamCooker/SteamCooker.geom.usd new file mode 100755 index 0000000000..4874fe9b38 Binary files /dev/null and b/testsuite/test_0016/data/assets/SteamCooker/SteamCooker.geom.usd differ diff --git a/testsuite/test_0016/data/assets/SteamCooker/SteamCooker.usd b/testsuite/test_0016/data/assets/SteamCooker/SteamCooker.usd new file mode 100755 index 0000000000..d674d9afbb --- /dev/null +++ b/testsuite/test_0016/data/assets/SteamCooker/SteamCooker.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "SteamCooker" + upAxis = "Z" +) + +def Xform "SteamCooker" ( + assetInfo = { + asset identifier = @./assets/SteamCooker/SteamCooker.usd@ + string name = "SteamCooker" + } + kind = "component" + payload = @./SteamCooker_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/SteamCooker/SteamCooker_payload.usd b/testsuite/test_0016/data/assets/SteamCooker/SteamCooker_payload.usd new file mode 100755 index 0000000000..2afa9d6a8c --- /dev/null +++ b/testsuite/test_0016/data/assets/SteamCooker/SteamCooker_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "SteamCooker" + upAxis = "Z" +) + +def "SteamCooker" ( + assetInfo = { + asset identifier = @./assets/SteamCooker/SteamCooker.usd@ + string name = "SteamCooker" + } + add references = @./SteamCooker.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/StoolMetalWire/StoolMetalWire.geom.usd b/testsuite/test_0016/data/assets/StoolMetalWire/StoolMetalWire.geom.usd new file mode 100755 index 0000000000..a914c69cb2 Binary files /dev/null and b/testsuite/test_0016/data/assets/StoolMetalWire/StoolMetalWire.geom.usd differ diff --git a/testsuite/test_0016/data/assets/StoolMetalWire/StoolMetalWire.usd b/testsuite/test_0016/data/assets/StoolMetalWire/StoolMetalWire.usd new file mode 100755 index 0000000000..e80b575a3a --- /dev/null +++ b/testsuite/test_0016/data/assets/StoolMetalWire/StoolMetalWire.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "StoolMetalWire" + upAxis = "Z" +) + +def Xform "StoolMetalWire" ( + assetInfo = { + asset identifier = @./assets/StoolMetalWire/StoolMetalWire.usd@ + string name = "StoolMetalWire" + } + kind = "component" + payload = @./StoolMetalWire_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/StoolMetalWire/StoolMetalWire_payload.usd b/testsuite/test_0016/data/assets/StoolMetalWire/StoolMetalWire_payload.usd new file mode 100755 index 0000000000..5b0473bfcf --- /dev/null +++ b/testsuite/test_0016/data/assets/StoolMetalWire/StoolMetalWire_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "StoolMetalWire" + upAxis = "Z" +) + +def "StoolMetalWire" ( + assetInfo = { + asset identifier = @./assets/StoolMetalWire/StoolMetalWire.usd@ + string name = "StoolMetalWire" + } + add references = @./StoolMetalWire.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/StoolWooden/StoolWooden.geom.usd b/testsuite/test_0016/data/assets/StoolWooden/StoolWooden.geom.usd new file mode 100755 index 0000000000..5a31235bbb Binary files /dev/null and b/testsuite/test_0016/data/assets/StoolWooden/StoolWooden.geom.usd differ diff --git a/testsuite/test_0016/data/assets/StoolWooden/StoolWooden.usd b/testsuite/test_0016/data/assets/StoolWooden/StoolWooden.usd new file mode 100755 index 0000000000..a5fcbf3d66 --- /dev/null +++ b/testsuite/test_0016/data/assets/StoolWooden/StoolWooden.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "StoolWooden" + upAxis = "Z" +) + +def Xform "StoolWooden" ( + assetInfo = { + asset identifier = @./assets/StoolWooden/StoolWooden.usd@ + string name = "StoolWooden" + } + kind = "component" + payload = @./StoolWooden_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/StoolWooden/StoolWooden_payload.usd b/testsuite/test_0016/data/assets/StoolWooden/StoolWooden_payload.usd new file mode 100755 index 0000000000..36b1b4c6fc --- /dev/null +++ b/testsuite/test_0016/data/assets/StoolWooden/StoolWooden_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "StoolWooden" + upAxis = "Z" +) + +def "StoolWooden" ( + assetInfo = { + asset identifier = @./assets/StoolWooden/StoolWooden.usd@ + string name = "StoolWooden" + } + add references = @./StoolWooden.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Stove/Stove.geom.usd b/testsuite/test_0016/data/assets/Stove/Stove.geom.usd new file mode 100755 index 0000000000..7b320b044d Binary files /dev/null and b/testsuite/test_0016/data/assets/Stove/Stove.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Stove/Stove.usd b/testsuite/test_0016/data/assets/Stove/Stove.usd new file mode 100755 index 0000000000..e36310f28d --- /dev/null +++ b/testsuite/test_0016/data/assets/Stove/Stove.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "Stove" + upAxis = "Z" +) + +def Xform "Stove" ( + assetInfo = { + asset identifier = @./assets/Stove/Stove.usd@ + string name = "Stove" + } + kind = "component" + payload = @./Stove_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Stove/Stove_payload.usd b/testsuite/test_0016/data/assets/Stove/Stove_payload.usd new file mode 100755 index 0000000000..5f8ab7f7ad --- /dev/null +++ b/testsuite/test_0016/data/assets/Stove/Stove_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Stove" + upAxis = "Z" +) + +def "Stove" ( + assetInfo = { + asset identifier = @./assets/Stove/Stove.usd@ + string name = "Stove" + } + add references = @./Stove.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Strainer/Strainer.geom.usd b/testsuite/test_0016/data/assets/Strainer/Strainer.geom.usd new file mode 100755 index 0000000000..dc361cf4f1 Binary files /dev/null and b/testsuite/test_0016/data/assets/Strainer/Strainer.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Strainer/Strainer.usd b/testsuite/test_0016/data/assets/Strainer/Strainer.usd new file mode 100755 index 0000000000..85ad73c470 --- /dev/null +++ b/testsuite/test_0016/data/assets/Strainer/Strainer.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "Strainer" + upAxis = "Z" +) + +def Xform "Strainer" ( + assetInfo = { + asset identifier = @./assets/Strainer/Strainer.usd@ + string name = "Strainer" + } + kind = "component" + payload = @./Strainer_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Strainer/Strainer_payload.usd b/testsuite/test_0016/data/assets/Strainer/Strainer_payload.usd new file mode 100755 index 0000000000..72738e2cf4 --- /dev/null +++ b/testsuite/test_0016/data/assets/Strainer/Strainer_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Strainer" + upAxis = "Z" +) + +def "Strainer" ( + assetInfo = { + asset identifier = @./assets/Strainer/Strainer.usd@ + string name = "Strainer" + } + add references = @./Strainer.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/TeaKettle/TeaKettle.geom.usd b/testsuite/test_0016/data/assets/TeaKettle/TeaKettle.geom.usd new file mode 100755 index 0000000000..644aa5fbfc Binary files /dev/null and b/testsuite/test_0016/data/assets/TeaKettle/TeaKettle.geom.usd differ diff --git a/testsuite/test_0016/data/assets/TeaKettle/TeaKettle.usd b/testsuite/test_0016/data/assets/TeaKettle/TeaKettle.usd new file mode 100755 index 0000000000..a1bef71e82 --- /dev/null +++ b/testsuite/test_0016/data/assets/TeaKettle/TeaKettle.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "TeaKettle" + upAxis = "Z" +) + +def Xform "TeaKettle" ( + assetInfo = { + asset identifier = @./assets/TeaKettle/TeaKettle.usd@ + string name = "TeaKettle" + } + kind = "component" + payload = @./TeaKettle_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/TeaKettle/TeaKettle_payload.usd b/testsuite/test_0016/data/assets/TeaKettle/TeaKettle_payload.usd new file mode 100755 index 0000000000..f905f6858c --- /dev/null +++ b/testsuite/test_0016/data/assets/TeaKettle/TeaKettle_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "TeaKettle" + upAxis = "Z" +) + +def "TeaKettle" ( + assetInfo = { + asset identifier = @./assets/TeaKettle/TeaKettle.usd@ + string name = "TeaKettle" + } + add references = @./TeaKettle.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/TinCan/TinCan.geom.usd b/testsuite/test_0016/data/assets/TinCan/TinCan.geom.usd new file mode 100755 index 0000000000..70e47e4e52 Binary files /dev/null and b/testsuite/test_0016/data/assets/TinCan/TinCan.geom.usd differ diff --git a/testsuite/test_0016/data/assets/TinCan/TinCan.usd b/testsuite/test_0016/data/assets/TinCan/TinCan.usd new file mode 100755 index 0000000000..7150f99152 --- /dev/null +++ b/testsuite/test_0016/data/assets/TinCan/TinCan.usd @@ -0,0 +1,30 @@ +#usda 1.0 +( + defaultPrim = "TinCan" + upAxis = "Z" +) + +def Xform "TinCan" ( + assetInfo = { + asset identifier = @./assets/TinCan/TinCan.usd@ + string name = "TinCan" + } + kind = "component" + payload = @./TinCan_payload.usd@ + variants = { + string modelingVariant = "TinCanA" + } + add variantSets = ["modelingVariant"] +) +{ + variantSet "modelingVariant" = { + "TinCanA" { + + } + "TinCanB" { + + } + } +} + + diff --git a/testsuite/test_0016/data/assets/TinCan/TinCan_payload.usd b/testsuite/test_0016/data/assets/TinCan/TinCan_payload.usd new file mode 100755 index 0000000000..3d8266cc3a --- /dev/null +++ b/testsuite/test_0016/data/assets/TinCan/TinCan_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "TinCan" + upAxis = "Z" +) + +def "TinCan" ( + assetInfo = { + asset identifier = @./assets/TinCan/TinCan.usd@ + string name = "TinCan" + } + add references = @./TinCan.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Toaster/Toaster.geom.usd b/testsuite/test_0016/data/assets/Toaster/Toaster.geom.usd new file mode 100755 index 0000000000..3c2fd46751 Binary files /dev/null and b/testsuite/test_0016/data/assets/Toaster/Toaster.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Toaster/Toaster.usd b/testsuite/test_0016/data/assets/Toaster/Toaster.usd new file mode 100755 index 0000000000..07111d3368 --- /dev/null +++ b/testsuite/test_0016/data/assets/Toaster/Toaster.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "Toaster" + upAxis = "Z" +) + +def Xform "Toaster" ( + assetInfo = { + asset identifier = @./assets/Toaster/Toaster.usd@ + string name = "Toaster" + } + kind = "component" + payload = @./Toaster_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Toaster/Toaster_payload.usd b/testsuite/test_0016/data/assets/Toaster/Toaster_payload.usd new file mode 100755 index 0000000000..e68d205770 --- /dev/null +++ b/testsuite/test_0016/data/assets/Toaster/Toaster_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Toaster" + upAxis = "Z" +) + +def "Toaster" ( + assetInfo = { + asset identifier = @./assets/Toaster/Toaster.usd@ + string name = "Toaster" + } + add references = @./Toaster.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/WallApple/WallApple.geom.usd b/testsuite/test_0016/data/assets/WallApple/WallApple.geom.usd new file mode 100755 index 0000000000..6d47de8694 Binary files /dev/null and b/testsuite/test_0016/data/assets/WallApple/WallApple.geom.usd differ diff --git a/testsuite/test_0016/data/assets/WallApple/WallApple.usd b/testsuite/test_0016/data/assets/WallApple/WallApple.usd new file mode 100755 index 0000000000..99e783236a --- /dev/null +++ b/testsuite/test_0016/data/assets/WallApple/WallApple.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "WallApple" + upAxis = "Z" +) + +def Xform "WallApple" ( + assetInfo = { + asset identifier = @./assets/WallApple/WallApple.usd@ + string name = "WallApple" + } + kind = "component" + payload = @./WallApple_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/WallApple/WallApple_payload.usd b/testsuite/test_0016/data/assets/WallApple/WallApple_payload.usd new file mode 100755 index 0000000000..1ba5b70cb3 --- /dev/null +++ b/testsuite/test_0016/data/assets/WallApple/WallApple_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "WallApple" + upAxis = "Z" +) + +def "WallApple" ( + assetInfo = { + asset identifier = @./assets/WallApple/WallApple.usd@ + string name = "WallApple" + } + add references = @./WallApple.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/WallBanana/WallBanana.geom.usd b/testsuite/test_0016/data/assets/WallBanana/WallBanana.geom.usd new file mode 100755 index 0000000000..dbdc1d4032 Binary files /dev/null and b/testsuite/test_0016/data/assets/WallBanana/WallBanana.geom.usd differ diff --git a/testsuite/test_0016/data/assets/WallBanana/WallBanana.usd b/testsuite/test_0016/data/assets/WallBanana/WallBanana.usd new file mode 100755 index 0000000000..c0726b1c8e --- /dev/null +++ b/testsuite/test_0016/data/assets/WallBanana/WallBanana.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "WallBanana" + upAxis = "Z" +) + +def Xform "WallBanana" ( + assetInfo = { + asset identifier = @./assets/WallBanana/WallBanana.usd@ + string name = "WallBanana" + } + kind = "component" + payload = @./WallBanana_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/WallBanana/WallBanana_payload.usd b/testsuite/test_0016/data/assets/WallBanana/WallBanana_payload.usd new file mode 100755 index 0000000000..c7cefb5f44 --- /dev/null +++ b/testsuite/test_0016/data/assets/WallBanana/WallBanana_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "WallBanana" + upAxis = "Z" +) + +def "WallBanana" ( + assetInfo = { + asset identifier = @./assets/WallBanana/WallBanana.usd@ + string name = "WallBanana" + } + add references = @./WallBanana.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/WallFlower/WallFlower.geom.usd b/testsuite/test_0016/data/assets/WallFlower/WallFlower.geom.usd new file mode 100755 index 0000000000..432e59ee71 Binary files /dev/null and b/testsuite/test_0016/data/assets/WallFlower/WallFlower.geom.usd differ diff --git a/testsuite/test_0016/data/assets/WallFlower/WallFlower.usd b/testsuite/test_0016/data/assets/WallFlower/WallFlower.usd new file mode 100755 index 0000000000..dc6c88eb59 --- /dev/null +++ b/testsuite/test_0016/data/assets/WallFlower/WallFlower.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "WallFlower" + upAxis = "Z" +) + +def Xform "WallFlower" ( + assetInfo = { + asset identifier = @./assets/WallFlower/WallFlower.usd@ + string name = "WallFlower" + } + kind = "component" + payload = @./WallFlower_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/WallFlower/WallFlower_payload.usd b/testsuite/test_0016/data/assets/WallFlower/WallFlower_payload.usd new file mode 100755 index 0000000000..e3bf700cbb --- /dev/null +++ b/testsuite/test_0016/data/assets/WallFlower/WallFlower_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "WallFlower" + upAxis = "Z" +) + +def "WallFlower" ( + assetInfo = { + asset identifier = @./assets/WallFlower/WallFlower.usd@ + string name = "WallFlower" + } + add references = @./WallFlower.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/WallOrange/WallOrange.geom.usd b/testsuite/test_0016/data/assets/WallOrange/WallOrange.geom.usd new file mode 100755 index 0000000000..ee4d553826 Binary files /dev/null and b/testsuite/test_0016/data/assets/WallOrange/WallOrange.geom.usd differ diff --git a/testsuite/test_0016/data/assets/WallOrange/WallOrange.usd b/testsuite/test_0016/data/assets/WallOrange/WallOrange.usd new file mode 100755 index 0000000000..a88f601a33 --- /dev/null +++ b/testsuite/test_0016/data/assets/WallOrange/WallOrange.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "WallOrange" + upAxis = "Z" +) + +def Xform "WallOrange" ( + assetInfo = { + asset identifier = @./assets/WallOrange/WallOrange.usd@ + string name = "WallOrange" + } + kind = "component" + payload = @./WallOrange_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/WallOrange/WallOrange_payload.usd b/testsuite/test_0016/data/assets/WallOrange/WallOrange_payload.usd new file mode 100755 index 0000000000..d630891575 --- /dev/null +++ b/testsuite/test_0016/data/assets/WallOrange/WallOrange_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "WallOrange" + upAxis = "Z" +) + +def "WallOrange" ( + assetInfo = { + asset identifier = @./assets/WallOrange/WallOrange.usd@ + string name = "WallOrange" + } + add references = @./WallOrange.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/WallPineapple/WallPineapple.geom.usd b/testsuite/test_0016/data/assets/WallPineapple/WallPineapple.geom.usd new file mode 100755 index 0000000000..d40fee7748 Binary files /dev/null and b/testsuite/test_0016/data/assets/WallPineapple/WallPineapple.geom.usd differ diff --git a/testsuite/test_0016/data/assets/WallPineapple/WallPineapple.usd b/testsuite/test_0016/data/assets/WallPineapple/WallPineapple.usd new file mode 100755 index 0000000000..c61de40332 --- /dev/null +++ b/testsuite/test_0016/data/assets/WallPineapple/WallPineapple.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "WallPineapple" + upAxis = "Z" +) + +def Xform "WallPineapple" ( + assetInfo = { + asset identifier = @./assets/WallPineapple/WallPineapple.usd@ + string name = "WallPineapple" + } + kind = "component" + payload = @./WallPineapple_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/WallPineapple/WallPineapple_payload.usd b/testsuite/test_0016/data/assets/WallPineapple/WallPineapple_payload.usd new file mode 100755 index 0000000000..0f3419efc6 --- /dev/null +++ b/testsuite/test_0016/data/assets/WallPineapple/WallPineapple_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "WallPineapple" + upAxis = "Z" +) + +def "WallPineapple" ( + assetInfo = { + asset identifier = @./assets/WallPineapple/WallPineapple.usd@ + string name = "WallPineapple" + } + add references = @./WallPineapple.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Whisk/Whisk.geom.usd b/testsuite/test_0016/data/assets/Whisk/Whisk.geom.usd new file mode 100755 index 0000000000..7a140d6f73 Binary files /dev/null and b/testsuite/test_0016/data/assets/Whisk/Whisk.geom.usd differ diff --git a/testsuite/test_0016/data/assets/Whisk/Whisk.usd b/testsuite/test_0016/data/assets/Whisk/Whisk.usd new file mode 100755 index 0000000000..c4ddb3b50e --- /dev/null +++ b/testsuite/test_0016/data/assets/Whisk/Whisk.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "Whisk" + upAxis = "Z" +) + +def Xform "Whisk" ( + assetInfo = { + asset identifier = @./assets/Whisk/Whisk.usd@ + string name = "Whisk" + } + kind = "component" + payload = @./Whisk_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/Whisk/Whisk_payload.usd b/testsuite/test_0016/data/assets/Whisk/Whisk_payload.usd new file mode 100755 index 0000000000..252ed71c48 --- /dev/null +++ b/testsuite/test_0016/data/assets/Whisk/Whisk_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "Whisk" + upAxis = "Z" +) + +def "Whisk" ( + assetInfo = { + asset identifier = @./assets/Whisk/Whisk.usd@ + string name = "Whisk" + } + add references = @./Whisk.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/WoodenDryingRack/WoodenDryingRack.geom.usd b/testsuite/test_0016/data/assets/WoodenDryingRack/WoodenDryingRack.geom.usd new file mode 100755 index 0000000000..7f47dc1ecb Binary files /dev/null and b/testsuite/test_0016/data/assets/WoodenDryingRack/WoodenDryingRack.geom.usd differ diff --git a/testsuite/test_0016/data/assets/WoodenDryingRack/WoodenDryingRack.usd b/testsuite/test_0016/data/assets/WoodenDryingRack/WoodenDryingRack.usd new file mode 100755 index 0000000000..04b0f637b0 --- /dev/null +++ b/testsuite/test_0016/data/assets/WoodenDryingRack/WoodenDryingRack.usd @@ -0,0 +1,18 @@ +#usda 1.0 +( + defaultPrim = "WoodenDryingRack" + upAxis = "Z" +) + +def Xform "WoodenDryingRack" ( + assetInfo = { + asset identifier = @./assets/WoodenDryingRack/WoodenDryingRack.usd@ + string name = "WoodenDryingRack" + } + kind = "component" + payload = @./WoodenDryingRack_payload.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/WoodenDryingRack/WoodenDryingRack_payload.usd b/testsuite/test_0016/data/assets/WoodenDryingRack/WoodenDryingRack_payload.usd new file mode 100755 index 0000000000..63740f34a0 --- /dev/null +++ b/testsuite/test_0016/data/assets/WoodenDryingRack/WoodenDryingRack_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "WoodenDryingRack" + upAxis = "Z" +) + +def "WoodenDryingRack" ( + assetInfo = { + asset identifier = @./assets/WoodenDryingRack/WoodenDryingRack.usd@ + string name = "WoodenDryingRack" + } + add references = @./WoodenDryingRack.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/assets/WoodenSpoon/WoodenSpoon.geom.usd b/testsuite/test_0016/data/assets/WoodenSpoon/WoodenSpoon.geom.usd new file mode 100755 index 0000000000..f57d65c8e3 Binary files /dev/null and b/testsuite/test_0016/data/assets/WoodenSpoon/WoodenSpoon.geom.usd differ diff --git a/testsuite/test_0016/data/assets/WoodenSpoon/WoodenSpoon.usd b/testsuite/test_0016/data/assets/WoodenSpoon/WoodenSpoon.usd new file mode 100755 index 0000000000..c5ee69c91e --- /dev/null +++ b/testsuite/test_0016/data/assets/WoodenSpoon/WoodenSpoon.usd @@ -0,0 +1,30 @@ +#usda 1.0 +( + defaultPrim = "WoodenSpoon" + upAxis = "Z" +) + +def Xform "WoodenSpoon" ( + assetInfo = { + asset identifier = @./assets/WoodenSpoon/WoodenSpoon.usd@ + string name = "WoodenSpoon" + } + kind = "component" + payload = @./WoodenSpoon_payload.usd@ + variants = { + string modelingVariant = "WoodenSpoonA" + } + add variantSets = ["modelingVariant"] +) +{ + variantSet "modelingVariant" = { + "WoodenSpoonA" { + + } + "WoodenSpoonB" { + + } + } +} + + diff --git a/testsuite/test_0016/data/assets/WoodenSpoon/WoodenSpoon_payload.usd b/testsuite/test_0016/data/assets/WoodenSpoon/WoodenSpoon_payload.usd new file mode 100755 index 0000000000..f1a38c9693 --- /dev/null +++ b/testsuite/test_0016/data/assets/WoodenSpoon/WoodenSpoon_payload.usd @@ -0,0 +1,17 @@ +#usda 1.0 +( + defaultPrim = "WoodenSpoon" + upAxis = "Z" +) + +def "WoodenSpoon" ( + assetInfo = { + asset identifier = @./assets/WoodenSpoon/WoodenSpoon.usd@ + string name = "WoodenSpoon" + } + add references = @./WoodenSpoon.geom.usd@ +) +{ +} + + diff --git a/testsuite/test_0016/data/test.ass b/testsuite/test_0016/data/test.ass new file mode 100755 index 0000000000..2af079d845 --- /dev/null +++ b/testsuite/test_0016/data/test.ass @@ -0,0 +1,114 @@ +### exported: Mon Dec 17 21:54:24 2018 +### from: Arnold 5.2.2.0 [30b8ba14] windows icc-17.0.2 oiio-2.0.1 osl-1.10.1 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 2018/12/04 22:02:04 +### host app: MtoA 3.1.3.wip 7d48f6c4 (develop) Maya 2018 +### bounds: -1 -8.268288 -1 1 -6.268287 1 +### user: blaines +### render_layer: defaultRenderLayer +### scene: D:/arnold/scenes/usd.ma + + + +options +{ + AA_samples 3 + outputs "RGBA RGBA myfilter mydriver" + xres 160 + yres 120 + pixel_aspect_ratio 1.33333325 + camera "perspShape" + frame 1 +} + +gaussian_filter +{ + name myfilter +} + +driver_tiff +{ + name mydriver + filename "testrender.tif" + color_space "sRGB" +} + +persp_camera +{ + name perspShape + matrix + 0.999945164 8.67361738e-19 0.0104717845 0 + -0.0104540139 0.0582322851 0.998248339 0 + -0.000609795912 -0.998303056 0.0582290925 0 + 53.1155281 -643.779846 144.040329 1 + near_clip 0.100000001 + far_clip 10000 + shutter_start 0 + shutter_end 0 + shutter_type "box" + rolling_shutter "off" + rolling_shutter_duration 0 + motion_start 0 + motion_end 0 + exposure 0 + fov 54.4322243 + uv_remap 0 0 0 1 + declare dcc_name constant STRING + dcc_name "perspShape" +} + +skydome_light +{ + name |aiSkyDomeLight1|aiSkyDomeLightShape1 + exposure 0 + cast_shadows on + cast_volumetric_shadows on + shadow_density 1 + shadow_color 0 0 0 + samples 1 + normalize on + camera 0 + transmission 1 + diffuse 1 + specular 1 + sss 1 + indirect 1 + max_bounces 999 + volume_samples 2 + volume 1 + aov "default" + resolution 1000 + format "latlong" + portal_mode "interior_only" + aov_indirect off + declare dcc_name constant STRING + dcc_name "aiSkyDomeLightShape1" +} + + +usd +{ + name aiUsdShape2 + visibility 255 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 -7.26828718 0 1 + use_light_group off + override_nodes off + threads 1 + debug off + filename "Kitchen_set.usd" + shader surfShader +} +standard_surface +{ + name surfShader + base_color userData +} + +user_data_rgb +{ + name userData + attribute "displayColor" + +} diff --git a/testsuite/test_0016/ref/reference.log b/testsuite/test_0016/ref/reference.log new file mode 100755 index 0000000000..8280505d42 --- /dev/null +++ b/testsuite/test_0016/ref/reference.log @@ -0,0 +1,3161 @@ +00:00:00 61MB | log started Fri May 17 14:01:47 2019 +00:00:00 61MB | Arnold 5.3.0.0 [b452526e] windows icc-17.0.2 oiio-2.1.0 osl-1.11.0 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 optix-6.0.0 2019/03/20 01:03:22 +00:00:00 61MB | running on REM8WCK8D2, pid=14924 +00:00:00 61MB | 2 x Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz (20 cores, 40 logical) with 65456MB +00:00:00 61MB | NVIDIA driver version 430.64 +00:00:00 61MB | GPU 0: GeForce RTX 2080 Ti @ 1635MHz (compute 7.5) with 11264MB (10769MB available) (NVLink:0) +00:00:00 61MB | GPU 1: Quadro K620 @ 1124MHz (compute 5.0) with 2048MB (1379MB available) (NVLink:0) +00:00:00 61MB | Windows 7 Enterprise Edition Service Pack 1 (version 6.1, build 7601) +00:00:00 61MB | soft limit for open files raised from 512 to 2048 +00:00:00 61MB | +00:00:00 61MB | loading plugins from D:\arnold\usd_procedural\build\windows_x86_64\msvc_opt\usd-0.18.11_arnold-5.3.0.0\procedural ... +00:00:00 61MB | usd_proc.dll: usd uses Arnold 5.3.0.0 +00:00:00 61MB | loaded 1 plugins from 1 lib(s) in 0:00.08 +00:00:00 61MB | loading plugins from D:\arnold\releases\Arnold_latest-windows-usd\bin\..\plugins ... +00:00:00 61MB | no plugins loaded +00:00:00 61MB | [kick] command: D:\arnold\releases\Arnold_latest-windows-usd\bin\kick test.ass -dw -r 160 120 -bs 16 -o testrender.tif -set driver_tiff.dither false -nocrashpopup -dp -v 6 +00:00:00 61MB | loading plugins from . ... +00:00:00 61MB | no plugins loaded +00:00:00 61MB | [metadata] loading metadata file: test.ass +00:00:00 62MB | [ass] loading test.ass ... +00:00:00 62MB | [ass] read 1926 bytes, 8 nodes in 0:00.00 +00:00:00 62MB | [kick] applying 1 attr value override +00:00:00 62MB | +00:00:00 62MB | authorizing with default license managers: rlm, clm ... +00:00:02 70MB | [clm] authorized for "86985ARNOL_2018_0F" in 0:02.36 +00:00:02 70MB | [clm] expiration date: permanent, in use: 1/1000 +00:00:02 70MB | +00:00:02 70MB | [color_manager] no color manager is active +00:00:02 70MB | [color_manager] rendering color space is "linear" with declared chromaticities: +00:00:02 70MB | r(0.6400, 0.3300) g(0.3000, 0.6000) b(0.1500, 0.0600) and w(0.3127, 0.3290) +00:00:02 81MB | +00:00:02 81MB | there are 1 light and 2 objects: +00:00:02 81MB | 1 persp_camera +00:00:02 81MB | 1 skydome_light +00:00:02 81MB | 1 utility +00:00:02 81MB | 1 standard_surface +00:00:02 81MB | 1 user_data_rgb +00:00:02 81MB | 1 driver_tiff +00:00:02 81MB | 1 gaussian_filter +00:00:02 81MB | 1 list_aggregate +00:00:02 81MB | 1 usd +00:00:02 81MB | +00:00:02 81MB | rendering image at 160 x 120, 3 AA samples +00:00:02 81MB | AA samples max +00:00:02 81MB | AA sample clamp +00:00:02 81MB | diffuse +00:00:02 81MB | specular +00:00:02 81MB | transmission samples 2 / depth 2 +00:00:02 81MB | volume indirect +00:00:02 81MB | total depth 10 +00:00:02 81MB | bssrdf samples 2 +00:00:02 81MB | transparency depth 10 +00:00:02 81MB | initializing 10 nodes ... +OUT +00:00:02 148MB | [proc] aiUsdShape2: loaded 1788 nodes (1788 objects, 0 shaders) +00:00:02 148MB | creating root object list ... +00:00:02 148MB | node initialization done in 0:00.38 (multithreaded) +00:00:02 148MB | updating 1799 nodes ... +00:00:02 148MB | |aiSkyDomeLight1|aiSkyDomeLightShape1: skydome_light using 1 sample, 2 volume samples +00:00:02 148MB | scene bounds: (-221.34317 -259.580536 -5.56548309) -> (363.558838 189.715439 348.988098) +00:00:02 148MB | node update done in 0:00.00 (multithreaded) +00:00:02 148MB | [aov] parsing 1 output statements ... +00:00:02 148MB | [aov] registered driver: "mydriver" (driver_tiff) +00:00:02 148MB | [aov] * "RGBA" of type RGBA filtered by "myfilter" (gaussian_filter) +00:00:02 148MB | [aov] done preparing 2 AOVs for 1 output to 1 driver (0 deep AOVs) +00:00:02 149MB | starting 40 bucket workers of size 16x16 ... +00:00:02 154MB | [accel] procedural bvh4 done - 0:00.00 (wall time) - 1788 prims, 1 key +00:00:02 154MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Ceiling/pPlane5: regular subdivision done - 1 iterations: 1 faces => 4 quads - 0:00.00 +00:00:02 154MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Ceiling/pPlane20: regular subdivision done - 1 iterations: 1 faces => 4 quads - 0:00.00 +00:00:02 155MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane290: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 155MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/Iron_1/Geom/pPlane339: regular subdivision done - 1 iterations: 110 faces => 440 quads - 0:00.00 +00:00:02 155MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane173: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 155MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane168: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 156MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane161: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 157MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane185: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 158MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Body/pPlane2: regular subdivision done - 1 iterations: 120 faces => 480 quads - 0:00.00 +00:00:02 158MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane163: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 160MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/pCube414: regular subdivision done - 1 iterations: 168 faces => 672 quads - 0:00.00 +00:00:02 164MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent11: regular subdivision done - 1 iterations: 252 faces => 1008 quads - 0:00.00 +00:00:02 164MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 4 prims, 1 key +00:00:02 164MB | [subdiv] /Kitchen_set/Props_grp/West_grp/IronBoard_1/Geom/IroningBoard/pPlane311: regular subdivision done - 1 iterations: 288 faces => 1152 quads - 0:00.00 +00:00:02 164MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 4 prims, 1 key +00:00:02 165MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 440 prims, 1 key +00:00:02 165MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:02 165MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:02 165MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:02 165MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:02 165MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:02 165MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Windows_Frame/pCube421: regular subdivision done - 1 iterations: 300 faces => 1200 quads - 0:00.00 +00:00:02 165MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Counter/Counter_edge: regular subdivision done - 1 iterations: 422 faces => 1687 quads - 0:00.00 +00:00:02 165MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 672 prims, 1 key +00:00:02 165MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 480 prims, 1 key +00:00:02 165MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Body/polySurface72: regular subdivision done - 1 iterations: 80 faces => 320 quads - 0:00.00 +00:00:02 165MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1008 prims, 1 key +00:00:02 165MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane347: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 165MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:02 165MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane184: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 165MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1152 prims, 1 key +00:00:02 165MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 320 prims, 1 key +00:00:02 165MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:02 165MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Ceiling/pCube299: regular subdivision done - 1 iterations: 170 faces => 680 quads - 0:00.00 +00:00:02 165MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane177: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 165MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:02 166MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube306: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 166MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Body/pCube333: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 166MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1200 prims, 1 key +00:00:02 166MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Doors/pCube15: regular subdivision done - 1 iterations: 114 faces => 456 quads - 0:00.00 +00:00:02 166MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent7: regular subdivision done - 1 iterations: 168 faces => 672 quads - 0:00.00 +00:00:02 166MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane172: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 167MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1687 prims, 1 key +00:00:02 167MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:02 167MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:02 168MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Body/pCube332: regular subdivision done - 1 iterations: 112 faces => 448 quads - 0:00.00 +00:00:02 167MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Windows_Frame/WindowBig/pCube31: regular subdivision done - 1 iterations: 182 faces => 728 quads - 0:00.00 +00:00:02 168MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 680 prims, 1 key +00:00:02 167MB | [subdiv] /Kitchen_set/Props_grp/Ceiling_grp/CeilingLight_1/Geom/pCylinder164: regular subdivision done - 1 iterations: 266 faces => 1036 quads - 0:00.00 +00:00:02 168MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent34: regular subdivision done - 1 iterations: 110 faces => 440 quads - 0:00.00 +00:00:02 168MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Body/polySurface39: regular subdivision done - 1 iterations: 208 faces => 832 quads - 0:00.00 +00:00:02 168MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Doors/pCube296: regular subdivision done - 1 iterations: 114 faces => 456 quads - 0:00.00 +00:00:02 169MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/KitchenTable_1/Geom/Edge: regular subdivision done - 1 iterations: 680 faces => 2720 quads - 0:00.00 +00:00:02 169MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Leaf/pPlane133: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:02 169MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Curtains1/L/nurbsToPoly24: regular subdivision done - 1 iterations: 200 faces => 798 quads - 0:00.00 +00:00:02 169MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube323: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 170MB | [subdiv] /Kitchen_set/Props_grp/West_grp/IronBoard_1/Geom/IroningBoard/pCylinder333: regular subdivision done - 1 iterations: 120 faces => 456 quads - 0:00.00 +00:00:02 171MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent5: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:02 171MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane260: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 171MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/Iron_1/Geom/IronWire/pCylinder350: regular subdivision done - 1 iterations: 330 faces => 1320 quads - 0:00.00 +00:00:02 172MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent3: regular subdivision done - 1 iterations: 126 faces => 504 quads - 0:00.00 +00:00:02 178MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane276: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 172MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:02 172MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:02 171MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 448 prims, 1 key +00:00:02 173MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 728 prims, 1 key +00:00:02 173MB | [subdiv] /Kitchen_set/Props_grp/West_grp/IronBoard_1/Geom/IroningBoard/pPlane314: regular subdivision done - 1 iterations: 306 faces => 1224 quads - 0:00.00 +00:00:02 173MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent25: regular subdivision done - 1 iterations: 110 faces => 440 quads - 0:00.00 +00:00:02 174MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane286: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 175MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:02 177MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent26: regular subdivision done - 1 iterations: 110 faces => 440 quads - 0:00.00 +00:00:02 176MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/PanB_1/Geom/pCylinder152: regular subdivision done - 1 iterations: 292 faces => 1150 quads - 0:00.00 +00:00:02 172MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane358: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 176MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent2: regular subdivision done - 1 iterations: 270 faces => 1080 quads - 0:00.00 +00:00:02 176MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 440 prims, 1 key +00:00:02 178MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:02 178MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:02 178MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Body/DustPan2: regular subdivision done - 1 iterations: 508 faces => 2032 quads - 0:00.00 +00:00:02 178MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 832 prims, 1 key +00:00:02 178MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1036 prims, 1 key +00:00:02 178MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 798 prims, 1 key +00:00:02 178MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Body/pCube285: regular subdivision done - 1 iterations: 148 faces => 592 quads - 0:00.00 +00:00:02 172MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 456 prims, 1 key +00:00:02 178MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:02 178MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane229: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 178MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1320 prims, 1 key +00:00:02 178MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 504 prims, 1 key +00:00:02 178MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent1: regular subdivision done - 1 iterations: 294 faces => 1176 quads - 0:00.00 +00:00:02 178MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2720 prims, 1 key +00:00:02 178MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent10: regular subdivision done - 1 iterations: 216 faces => 864 quads - 0:00.00 +00:00:02 178MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 440 prims, 1 key +00:00:02 178MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Doorknobs/pSphere31: regular subdivision done - 1 iterations: 252 faces => 984 quads - 0:00.00 +00:00:02 179MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 864 prims, 1 key +00:00:02 175MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 456 prims, 1 key +00:00:02 175MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 672 prims, 1 key +00:00:02 177MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1224 prims, 1 key +00:00:02 177MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:02 177MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Body/pCube283: regular subdivision done - 1 iterations: 170 faces => 680 quads - 0:00.00 +00:00:02 177MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Sink_Curtain/nurbsToPoly22: regular subdivision done - 1 iterations: 1054 faces => 4216 quads - 0:00.01 +00:00:02 177MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:02 177MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:02 177MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1150 prims, 1 key +00:00:02 177MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1080 prims, 1 key +00:00:02 177MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Body/pCube230: regular subdivision done - 1 iterations: 1754 faces => 7022 quads - 0:00.01 +00:00:02 178MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 456 prims, 1 key +00:00:02 178MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane169: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 178MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane237: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 178MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Windows_Frame/WindowBig/pCube41: regular subdivision done - 1 iterations: 94 faces => 376 quads - 0:00.00 +00:00:02 179MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Body/polySurface52: regular subdivision done - 1 iterations: 180 faces => 720 quads - 0:00.00 +00:00:02 178MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane210: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 178MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 592 prims, 1 key +00:00:02 178MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2032 prims, 1 key +00:00:02 178MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/BreadBag_1/Geom/Bread: regular subdivision done - 1 iterations: 1818 faces => 7276 quads - 0:00.01 +00:00:02 178MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Windows_Frame/WindowStill/Window_Frame_Arch/pCube467: regular subdivision done - 1 iterations: 240 faces => 960 quads - 0:00.00 +00:00:02 179MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:02 179MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane236: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 178MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane359: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 179MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Body/pCube4: regular subdivision done - 1 iterations: 112 faces => 448 quads - 0:00.00 +00:00:02 177MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 440 prims, 1 key +00:00:02 179MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1176 prims, 1 key +00:00:02 179MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane187: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 180MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 984 prims, 1 key +00:00:02 180MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Sink/Body/Sink_Body: regular subdivision done - 1 iterations: 451 faces => 1808 quads - 0:00.00 +00:00:02 177MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/KitchenTable_1/Geom/Top: regular subdivision done - 1 iterations: 492 faces => 1968 quads - 0:00.00 +00:00:02 180MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane250: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 177MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Curtains1/Top: regular subdivision done - 1 iterations: 1342 faces => 5368 quads - 0:00.01 +00:00:02 179MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/KitchenTable_1/Geom/Legs/pCube187: regular subdivision done - 1 iterations: 6 faces => 24 quads - 0:00.00 +00:00:02 179MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane202: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 179MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Body/pCube294: regular subdivision done - 1 iterations: 112 faces => 448 quads - 0:00.00 +00:00:02 179MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/ChairB_1/Geom/pCylinder177: regular subdivision done - 1 iterations: 312 faces => 1248 quads - 0:00.00 +00:00:02 179MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 4216 prims, 1 key +00:00:02 178MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Rug: regular subdivision done - 1 iterations: 700 faces => 2800 quads - 0:00.00 +00:00:02 180MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:02 180MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane228: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 178MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Windows_Frame/WindowBig/pCube336: regular subdivision done - 1 iterations: 112 faces => 448 quads - 0:00.00 +00:00:02 183MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 376 prims, 1 key +00:00:02 183MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:02 183MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 720 prims, 1 key +00:00:02 174MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent17: regular subdivision done - 1 iterations: 444 faces => 1776 quads - 0:00.00 +00:00:02 185MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/Mixer_1/Geom/Cable/pCylinder255: regular subdivision done - 1 iterations: 420 faces => 1660 quads - 0:00.00 +00:00:02 185MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 7022 prims, 1 key +00:00:02 179MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube321: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 186MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:02 186MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 960 prims, 1 key +00:00:02 186MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Windows_Frame/WindowBig/pCube423: regular subdivision done - 1 iterations: 300 faces => 1200 quads - 0:00.00 +00:00:02 186MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 7276 prims, 1 key +00:00:02 186MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane182: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 186MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane292: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 186MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 448 prims, 1 key +00:00:02 186MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:02 186MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1808 prims, 1 key +00:00:02 186MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1968 prims, 1 key +00:00:02 186MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/pPlane86: regular subdivision done - 1 iterations: 5 faces => 20 quads - 0:00.00 +00:00:02 186MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Body/pCube328: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:02 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 24 prims, 1 key +00:00:02 189MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent9: regular subdivision done - 1 iterations: 704 faces => 2816 quads - 0:00.00 +00:00:02 190MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:02 190MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 448 prims, 1 key +00:00:02 180MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:02 189MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/TableTop_grp/PaperWrinkle_2/Geom/PaperWrinkle: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:02 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 5368 prims, 1 key +00:00:02 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2800 prims, 1 key +00:00:02 189MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/GarlicRope_1/Geom/pCylinder241: regular subdivision done - 1 iterations: 3010 faces => 12040 quads - 0:00.01 +00:00:03 190MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2816 prims, 1 key +00:00:02 189MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Counter/Counter_top: regular subdivision done - 1 iterations: 792 faces => 3168 quads - 0:00.00 +00:00:03 190MB | [subdiv] /Kitchen_set/Props_grp/West_grp/IronBoard_1/Geom/IroningBoard/pCylinder328: regular subdivision done - 1 iterations: 120 faces => 456 quads - 0:00.00 +00:00:03 190MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Windows_Frame/WindowBig/pCube360: regular subdivision done - 1 iterations: 94 faces => 376 quads - 0:00.00 +00:00:02 192MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane208: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 192MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 448 prims, 1 key +00:00:02 192MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Doors/pCube297: regular subdivision done - 1 iterations: 114 faces => 456 quads - 0:00.00 +00:00:02 186MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 376 prims, 1 key +00:00:02 190MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Knobs/pCylinder143: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 191MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 191MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1660 prims, 1 key +00:00:03 191MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1776 prims, 1 key +00:00:03 191MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/Strainer_1/Geom/pCylinder206: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 191MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1200 prims, 1 key +00:00:02 180MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 680 prims, 1 key +00:00:03 191MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 191MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Windows_Frame/WindowBig/pCube334: regular subdivision done - 1 iterations: 112 faces => 448 quads - 0:00.00 +00:00:03 191MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/BookBlue_1/Geom/pCube134: regular subdivision done - 1 iterations: 52 faces => 208 quads - 0:00.00 +00:00:02 179MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube347: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 191MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane197: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 191MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane227: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 191MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent18: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane171: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube193: regular subdivision done - 1 iterations: 296 faces => 1184 quads - 0:00.00 +00:00:02 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1248 prims, 1 key +00:00:03 189MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane271: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 189MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane348: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 185MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane207: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 190MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane77: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:02 192MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 187MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 456 prims, 1 key +00:00:02 180MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Windows_Frame/WindowBig/pCube33: regular subdivision done - 1 iterations: 96 faces => 384 quads - 0:00.00 +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane231: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 456 prims, 1 key +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 189MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane201: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 189MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube356: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 191MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 189MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane61: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 189MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent27: regular subdivision done - 1 iterations: 110 faces => 440 quads - 0:00.00 +00:00:03 189MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/pCube70: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 191MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 20 prims, 1 key +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 208 prims, 1 key +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 448 prims, 1 key +00:00:03 187MB | [accel] polymesh bvh4 done - 0:00.01 (wall time) - 12040 prims, 1 key +00:00:02 179MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane47: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 187MB | [subdiv] /Kitchen_set/Props_grp/West_grp/StoolMetalWire_1/Geom/polySurface63: regular subdivision done - 1 iterations: 14256 faces => 57024 quads - 0:00.09 +00:00:03 187MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 187MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Body/pCube277: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 187MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 187MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 187MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 187MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/TableTop_grp/PaperWrinkle_1/Geom/PaperWrinkle: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 187MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1184 prims, 1 key +00:00:03 187MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/ChairB_2/Geom/pCylinder177: regular subdivision done - 1 iterations: 312 faces => 1248 quads - 0:00.00 +00:00:03 187MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 187MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 187MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 191MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Curtains1/R/nurbsToPoly24: regular subdivision done - 1 iterations: 200 faces => 798 quads - 0:00.00 +00:00:03 187MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 384 prims, 1 key +00:00:03 187MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Ceiling/pCube298: regular subdivision done - 1 iterations: 170 faces => 680 quads - 0:00.00 +00:00:03 187MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube373: regular subdivision done - 1 iterations: 214 faces => 856 quads - 0:00.00 +00:00:03 187MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane247: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 187MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 187MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Body/polySurface34: regular subdivision done - 1 iterations: 180 faces => 720 quads - 0:00.00 +00:00:03 187MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 187MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 187MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder463: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 187MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube310: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 189MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/BottleLargeRose_1/Geom/pCylinder389: regular subdivision done - 1 iterations: 120 faces => 456 quads - 0:00.00 +00:00:03 187MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent15: regular subdivision done - 1 iterations: 216 faces => 864 quads - 0:00.00 +00:00:03 187MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/BookGreen_1/Geom/pCube134: regular subdivision done - 1 iterations: 52 faces => 208 quads - 0:00.00 +00:00:03 187MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 440 prims, 1 key +00:00:03 187MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 187MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 187MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane205: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 187MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Body/polySurface36: regular subdivision done - 1 iterations: 180 faces => 720 quads - 0:00.00 +00:00:03 187MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane42: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 187MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 185MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 3168 prims, 1 key +00:00:03 187MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Doors/polySurface96: regular subdivision done - 1 iterations: 128 faces => 512 quads - 0:00.00 +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane249: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Windows_Frame/WindowBig/pCube30: regular subdivision done - 1 iterations: 152 faces => 608 quads - 0:00.00 +00:00:03 187MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 189MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane199: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 189MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent8: regular subdivision done - 1 iterations: 520 faces => 2080 quads - 0:00.00 +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1248 prims, 1 key +00:00:03 189MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/CupShelf/Shelf/pCube25: regular subdivision done - 1 iterations: 168 faces => 672 quads - 0:00.00 +00:00:03 189MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/JarB_1/Geom/pCylinder59: regular subdivision done - 1 iterations: 140 faces => 540 quads - 0:00.00 +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 798 prims, 1 key +00:00:03 189MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent28: regular subdivision done - 1 iterations: 110 faces => 440 quads - 0:00.00 +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 856 prims, 1 key +00:00:03 189MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Body/pCube240: regular subdivision done - 1 iterations: 168 faces => 672 quads - 0:00.00 +00:00:03 187MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane160: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 189MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube357: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 720 prims, 1 key +00:00:03 187MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 864 prims, 1 key +00:00:03 187MB | [subdiv] /Kitchen_set/Props_grp/West_grp/IronBoard_1/Geom/IroningBoard/pCylinder334: regular subdivision done - 1 iterations: 120 faces => 456 quads - 0:00.00 +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 208 prims, 1 key +00:00:03 189MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane285: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 720 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane226: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 190MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube157: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 190MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 512 prims, 1 key +00:00:03 190MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent12: regular subdivision done - 1 iterations: 110 faces => 440 quads - 0:00.00 +00:00:03 190MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane274: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 190MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 608 prims, 1 key +00:00:03 190MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Windows_Frame/WindowBig/pCube422: regular subdivision done - 1 iterations: 300 faces => 1200 quads - 0:00.00 +00:00:03 190MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/TableTop_grp/PaperWrinkle_3/Geom/PaperWrinkle: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 190MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 190MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane167: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 189MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/GarlicRope_1/Geom/pCylinder307: regular subdivision done - 1 iterations: 520 faces => 2000 quads - 0:00.00 +00:00:03 190MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube319: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 190MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 440 prims, 1 key +00:00:03 190MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 540 prims, 1 key +00:00:03 190MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2080 prims, 1 key +00:00:03 189MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane190: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 190MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 672 prims, 1 key +00:00:03 190MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Windows_Frame/WindowBig/pCube36: regular subdivision done - 1 iterations: 126 faces => 504 quads - 0:00.00 +00:00:03 190MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/HandTowel_1/Geom/Towel: regular subdivision done - 1 iterations: 198 faces => 792 quads - 0:00.00 +00:00:03 190MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 187MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane356: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 190MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Body/pCube271: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 189MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/GarlicRope_1/Geom/pCylinder246: regular subdivision done - 1 iterations: 440 faces => 1680 quads - 0:00.00 +00:00:03 189MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/StoolWooden_1/Geom/pCylinder190: regular subdivision done - 1 iterations: 316 faces => 1224 quads - 0:00.00 +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.03 (wall time) - 57024 prims, 1 key +00:00:03 189MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Knobs/pCylinder140: regular subdivision done - 1 iterations: 252 faces => 984 quads - 0:00.00 +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 456 prims, 1 key +00:00:03 190MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 189MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Body/pCube282: regular subdivision done - 1 iterations: 112 faces => 448 quads - 0:00.00 +00:00:03 189MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Curtains1/R/polySurface73: regular subdivision done - 1 iterations: 413 faces => 1652 quads - 0:00.00 +00:00:03 189MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane300: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/RollingPin_1/Geom/pPipe27: regular subdivision done - 1 iterations: 110 faces => 440 quads - 0:00.00 +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 440 prims, 1 key +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 680 prims, 1 key +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1200 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent4: regular subdivision done - 1 iterations: 342 faces => 1368 quads - 0:00.00 +00:00:03 190MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 672 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane258: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/GarlicRope_1/Geom/pCylinder403: regular subdivision done - 1 iterations: 520 faces => 2000 quads - 0:00.00 +00:00:03 190MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane165: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 456 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Ceiling/pCube195: regular subdivision done - 1 iterations: 110 faces => 440 quads - 0:00.00 +00:00:03 188MB | [subdiv] /Kitchen_set/Props_grp/Ceiling_grp/CeilingLight_1/Geom/pCylinder163: regular subdivision done - 1 iterations: 132 faces => 504 quads - 0:00.00 +00:00:03 188MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/pCube413: regular subdivision done - 1 iterations: 168 faces => 672 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 504 prims, 1 key +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2000 prims, 1 key +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane78: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 672 prims, 1 key +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 792 prims, 1 key +00:00:03 189MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Windows_Frame/WindowBig/pCube32: regular subdivision done - 1 iterations: 96 faces => 384 quads - 0:00.00 +00:00:03 189MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube309: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1224 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane80: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Doors/pCube290: regular subdivision done - 1 iterations: 114 faces => 456 quads - 0:00.00 +00:00:03 188MB | [subdiv] /Kitchen_set/Props_grp/West_grp/IronBoard_1/Geom/IroningBoard/pCylinder335: regular subdivision done - 1 iterations: 120 faces => 456 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 984 prims, 1 key +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 448 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Doors/polySurface97: regular subdivision done - 1 iterations: 206 faces => 824 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 440 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent40: regular subdivision done - 1 iterations: 110 faces => 440 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent13: regular subdivision done - 1 iterations: 210 faces => 840 quads - 0:00.00 +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane69: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane361: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Body/pCube284: regular subdivision done - 1 iterations: 214 faces => 856 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Windows_Frame/WindowStill/Window_Frame_Arch/pCube466: regular subdivision done - 1 iterations: 240 faces => 960 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 960 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube322: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2000 prims, 1 key +00:00:03 189MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/BookTan_2/Geom/pCube134: regular subdivision done - 1 iterations: 52 faces => 208 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 504 prims, 1 key +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane214: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/PanA_1/Geom/polySurface80: regular subdivision done - 1 iterations: 132 faces => 504 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1680 prims, 1 key +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 384 prims, 1 key +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 456 prims, 1 key +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 456 prims, 1 key +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1652 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane240: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 824 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane242: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/GarlicRope_1/Geom/pCylinder283: regular subdivision done - 1 iterations: 440 faces => 1680 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 440 prims, 1 key +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 840 prims, 1 key +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1368 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/RollingPin_1/Geom/pCylinder323: regular subdivision done - 1 iterations: 220 faces => 860 quads - 0:00.00 +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane195: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder447: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane303: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Windows_Frame/WindowStill/Window_Frame_Arch/pCube79: regular subdivision done - 1 iterations: 292 faces => 1168 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 860 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane224: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Body/pCube327: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane159: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane241: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 208 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane75: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/BowlE_1/Geom/Bowl: regular subdivision done - 1 iterations: 320 faces => 1260 quads - 0:00.00 +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane279: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Handle/pPlane14: regular subdivision done - 1 iterations: 90 faces => 360 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 504 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Knobs/pCylinder139: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Curtains1/R/nurbsToPoly23: regular subdivision done - 1 iterations: 24 faces => 96 quads - 0:00.00 +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane72: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane218: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent33: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane166: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane268: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane254: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 440 prims, 1 key +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane246: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1680 prims, 1 key +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 856 prims, 1 key +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent21: regular subdivision done - 1 iterations: 94 faces => 376 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Ceiling/pCube300: regular subdivision done - 1 iterations: 88 faces => 352 quads - 0:00.00 +00:00:03 188MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/BookGreen_2/Geom/pCube134: regular subdivision done - 1 iterations: 52 faces => 208 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane65: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 189MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube314: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane189: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 190MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 360 prims, 1 key +00:00:03 190MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Props_grp/West_grp/StoolMetalWire_1/Geom/Ball1/polySurface93: regular subdivision done - 1 iterations: 140 faces => 520 quads - 0:00.00 +00:00:03 190MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 96 prims, 1 key +00:00:03 192MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent38: regular subdivision done - 1 iterations: 110 faces => 440 quads - 0:00.00 +00:00:03 190MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Props_grp/West_grp/IronBoard_1/Geom/IroningBoard/pPlane312: regular subdivision done - 1 iterations: 306 faces => 1224 quads - 0:00.00 +00:00:03 190MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane49: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 190MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 188MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/Strainer_1/Geom/pSphere53: regular subdivision done - 1 iterations: 915 faces => 3660 quads - 0:00.00 +00:00:03 191MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 191MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 191MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent35: regular subdivision done - 1 iterations: 168 faces => 672 quads - 0:00.00 +00:00:03 191MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane206: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 191MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane181: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 191MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 191MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Windows_Frame/WindowBig/pCube288: regular subdivision done - 1 iterations: 110 faces => 440 quads - 0:00.00 +00:00:03 188MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1168 prims, 1 key +00:00:03 192MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane204: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 192MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder450: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 192MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane245: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 192MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Body/pCube251: regular subdivision done - 1 iterations: 112 faces => 448 quads - 0:00.00 +00:00:03 189MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 192MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Windows_Frame/WindowBig/pCube359: regular subdivision done - 1 iterations: 94 faces => 376 quads - 0:00.00 +00:00:03 192MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Body/polySurface40: regular subdivision done - 1 iterations: 80 faces => 320 quads - 0:00.00 +00:00:03 192MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 352 prims, 1 key +00:00:03 192MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube350: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 192MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 192MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 192MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane44: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 190MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 192MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane275: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 192MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 520 prims, 1 key +00:00:03 190MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane235: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 192MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane296: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 191MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 193MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 193MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane291: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 191MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane289: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 193MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane261: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 193MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 672 prims, 1 key +00:00:03 191MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Windows_Frame/WindowBig/pCube338: regular subdivision done - 1 iterations: 126 faces => 504 quads - 0:00.00 +00:00:03 193MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 193MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 193MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane54: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 192MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 376 prims, 1 key +00:00:03 193MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane198: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 193MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 193MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 440 prims, 1 key +00:00:03 192MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 208 prims, 1 key +00:00:03 194MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 3660 prims, 1 key +00:00:03 194MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 448 prims, 1 key +00:00:03 190MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1260 prims, 1 key +00:00:03 195MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 320 prims, 1 key +00:00:03 195MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 376 prims, 1 key +00:00:03 195MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Handle/pPlane13: regular subdivision done - 1 iterations: 90 faces => 360 quads - 0:00.00 +00:00:03 195MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Ceiling/pCube301: regular subdivision done - 1 iterations: 110 faces => 440 quads - 0:00.00 +00:00:03 194MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 194MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/PaperTowelRoll_1/Geom/polySurface22: regular subdivision done - 1 iterations: 300 faces => 1200 quads - 0:00.00 +00:00:03 193MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Body/pCube330: regular subdivision done - 1 iterations: 112 faces => 448 quads - 0:00.00 +00:00:03 194MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane203: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 194MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 194MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 194MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane180: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 194MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 194MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane179: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 193MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/KitchenTable_1/Geom/Legs/pCube188: regular subdivision done - 1 iterations: 6 faces => 24 quads - 0:00.00 +00:00:03 193MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 193MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 193MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane162: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 193MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 193MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 193MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane83: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 193MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 193MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 193MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane213: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 193MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 504 prims, 1 key +00:00:03 194MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 193MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 193MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane174: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 193MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube355: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 193MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane164: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 193MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane158: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 193MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube307: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 194MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane298: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 193MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 440 prims, 1 key +00:00:03 193MB | [subdiv] /Kitchen_set/Props_grp/West_grp/PaperBagCrumpled_1/Geom/GroceryBag: regular subdivision done - 1 iterations: 4198 faces => 16792 quads - 0:00.02 +00:00:03 192MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 440 prims, 1 key +00:00:03 193MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane217: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 193MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube371: regular subdivision done - 1 iterations: 216 faces => 864 quads - 0:00.00 +00:00:03 193MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1224 prims, 1 key +00:00:03 193MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 195MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 864 prims, 1 key +00:00:03 193MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane251: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 193MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent6: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 193MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Ceiling/pCube199: regular subdivision done - 1 iterations: 170 faces => 680 quads - 0:00.00 +00:00:03 193MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 193MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/pPlane98: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 193MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane219: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 193MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 193MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 193MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane196: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 193MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane188: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 193MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder456: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 193MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 193MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane266: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 192MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 193MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 193MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 193MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane239: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 193MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 360 prims, 1 key +00:00:03 194MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 194MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 194MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 194MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 194MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 194MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane209: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 194MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1200 prims, 1 key +00:00:03 193MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane62: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 193MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 24 prims, 1 key +00:00:03 195MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane73: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 195MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 195MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane81: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 193MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane259: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 195MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 195MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane293: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 195MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 680 prims, 1 key +00:00:03 195MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane257: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 195MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 195MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 195MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane194: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 195MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 195MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 193MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Body/pCube243: regular subdivision done - 1 iterations: 188 faces => 752 quads - 0:00.00 +00:00:03 195MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/CastIron_1/Geom/pCylinder151: regular subdivision done - 1 iterations: 180 faces => 696 quads - 0:00.00 +00:00:03 197MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 752 prims, 1 key +00:00:03 195MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane50: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 195MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane252: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 196MB | [subdiv] /Kitchen_set/Props_grp/West_grp/SteamCooker_1/Geom/pCylinder55: regular subdivision done - 1 iterations: 256 faces => 984 quads - 0:00.00 +00:00:03 196MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane191: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 196MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane64: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 195MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 196MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent37: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 196MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/SaltShaker_1/Geom/pCylinder267: regular subdivision done - 1 iterations: 150 faces => 580 quads - 0:00.00 +00:00:03 196MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane92: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 196MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent29: regular subdivision done - 1 iterations: 110 faces => 440 quads - 0:00.00 +00:00:03 195MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 196MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 16792 prims, 1 key +00:00:03 196MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 196MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane256: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 193MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/BookTan_1/Geom/pCube134: regular subdivision done - 1 iterations: 52 faces => 208 quads - 0:00.00 +00:00:03 198MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group7/pCube379: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 197MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 197MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 197MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/pPlane116: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 193MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Windows_Frame/WindowBig/pCube289: regular subdivision done - 1 iterations: 110 faces => 440 quads - 0:00.00 +00:00:03 197MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 197MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane57: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 195MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 197MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/JarB_1/Geom/polySurface89: regular subdivision done - 1 iterations: 230 faces => 900 quads - 0:00.00 +00:00:03 197MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane183: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 193MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 448 prims, 1 key +00:00:03 197MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane212: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 197MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 197MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 696 prims, 1 key +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 900 prims, 1 key +00:00:03 196MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 196MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 984 prims, 1 key +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 198MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane63: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 196MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 198MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/AirVent/pPipe3: regular subdivision done - 1 iterations: 200 faces => 800 quads - 0:00.00 +00:00:03 198MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/BroomParts/pCylinder351: regular subdivision done - 1 iterations: 60 faces => 216 quads - 0:00.00 +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 580 prims, 1 key +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 440 prims, 1 key +00:00:03 198MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/GarlicRope_1/Geom/pCylinder240: regular subdivision done - 1 iterations: 2780 faces => 11120 quads - 0:00.01 +00:00:03 198MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane74: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 197MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 198MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/StoolWooden_1/Geom/pCylinder12: regular subdivision done - 1 iterations: 160 faces => 600 quads - 0:00.00 +00:00:03 197MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Body/pCube242: regular subdivision done - 1 iterations: 168 faces => 672 quads - 0:00.00 +00:00:03 198MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/ChairB_1/Geom/polySurface31: regular subdivision done - 1 iterations: 210 faces => 840 quads - 0:00.00 +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 440 prims, 1 key +00:00:03 198MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom2/pCylinder354: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 197MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 198MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane58: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 198MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/BookTan_2/Geom/Book: regular subdivision done - 1 iterations: 668 faces => 2672 quads - 0:00.00 +00:00:03 198MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane360: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 198MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube349: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 198MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/ChairB_2/Geom/polySurface29/polySurface88: regular subdivision done - 1 iterations: 104 faces => 416 quads - 0:00.00 +00:00:03 198MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Ceiling/pCube302: regular subdivision done - 1 iterations: 6 faces => 26 quads - 0:00.00 +00:00:03 198MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane284: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 198MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane273: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 198MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane232: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 198MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane295: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 216 prims, 1 key +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 800 prims, 1 key +00:00:03 198MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/SaltShakerShakerPepper_1/Geom/pCylinder267: regular subdivision done - 1 iterations: 150 faces => 580 quads - 0:00.00 +00:00:03 198MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/SoapDispenser_1/Geom/Body: regular subdivision done - 1 iterations: 284 faces => 1136 quads - 0:00.00 +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 198MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Doorknobs/pSphere30: regular subdivision done - 1 iterations: 252 faces => 984 quads - 0:00.00 +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 672 prims, 1 key +00:00:03 198MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Knobs/pCylinder141: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 198MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/Mixer_1/Geom/Body/pCylinder215: regular subdivision done - 1 iterations: 230 faces => 900 quads - 0:00.00 +00:00:03 198MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/CupA_1/Geom/pSphere8: regular subdivision done - 1 iterations: 260 faces => 1020 quads - 0:00.00 +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 840 prims, 1 key +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.01 (wall time) - 11120 prims, 1 key +00:00:03 198MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane277: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 198MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Ceiling/pCube303: regular subdivision done - 1 iterations: 110 faces => 440 quads - 0:00.00 +00:00:03 198MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/StoolWooden_1/Geom/pCube265: regular subdivision done - 1 iterations: 60 faces => 236 quads - 0:00.00 +00:00:03 198MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/ChairB_2/Geom/polySurface31: regular subdivision done - 1 iterations: 210 faces => 840 quads - 0:00.00 +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 198MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane288: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 199MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/GarlicRope_1/Geom/pCylinder310: regular subdivision done - 1 iterations: 520 faces => 2000 quads - 0:00.00 +00:00:03 198MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane220: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 199MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 26 prims, 1 key +00:00:03 200MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 416 prims, 1 key +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 198MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube351: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 199MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 199MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder527: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 199MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 199MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane294: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 199MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/pPlane104: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 199MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 199MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 580 prims, 1 key +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 199MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 984 prims, 1 key +00:00:03 199MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1136 prims, 1 key +00:00:03 199MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 199MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Handles/pCube207: regular subdivision done - 1 iterations: 86 faces => 344 quads - 0:00.00 +00:00:03 199MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Body/pCube273: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 199MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane221: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 200MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1020 prims, 1 key +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 440 prims, 1 key +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2672 prims, 1 key +00:00:03 199MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 840 prims, 1 key +00:00:03 200MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/pPlane96: regular subdivision done - 1 iterations: 360 faces => 1440 quads - 0:00.00 +00:00:03 200MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 200MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/GarlicRope_1/Geom/pCylinder311: regular subdivision done - 1 iterations: 520 faces => 2000 quads - 0:00.00 +00:00:03 200MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/ChairB_1/Geom/polySurface29/polySurface88: regular subdivision done - 1 iterations: 104 faces => 416 quads - 0:00.00 +00:00:03 200MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/ChairB_2/Geom/polySurface32: regular subdivision done - 1 iterations: 104 faces => 416 quads - 0:00.00 +00:00:03 200MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/pCube76: regular subdivision done - 1 iterations: 168 faces => 672 quads - 0:00.00 +00:00:03 200MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 200MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane270: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 200MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 200MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2000 prims, 1 key +00:00:03 199MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Ceiling/pCube304: regular subdivision done - 1 iterations: 88 faces => 352 quads - 0:00.00 +00:00:03 200MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 200MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 200MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane283: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 198MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane395: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 200MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane299: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 900 prims, 1 key +00:00:03 200MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Body/pCube326: regular subdivision done - 1 iterations: 112 faces => 448 quads - 0:00.00 +00:00:03 200MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/pPlane383: regular subdivision done - 1 iterations: 360 faces => 1440 quads - 0:00.00 +00:00:03 200MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 200MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 344 prims, 1 key +00:00:03 198MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/AirVent/pPipe11: regular subdivision done - 1 iterations: 894 faces => 3576 quads - 0:00.00 +00:00:03 200MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/KitchenTable_1/Geom/Legs/pCube189: regular subdivision done - 1 iterations: 6 faces => 24 quads - 0:00.00 +00:00:03 200MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane216: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 200MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/AirVent/pCube370: regular subdivision done - 1 iterations: 120 faces => 480 quads - 0:00.00 +00:00:03 197MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Body/pCube287: regular subdivision done - 1 iterations: 130 faces => 520 quads - 0:00.00 +00:00:03 200MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 416 prims, 1 key +00:00:03 201MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 480 prims, 1 key +00:00:03 200MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane357: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 200MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1440 prims, 1 key +00:00:03 200MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/GarlicRope_1/Geom/pCylinder305: regular subdivision done - 1 iterations: 520 faces => 2000 quads - 0:00.00 +00:00:03 200MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 416 prims, 1 key +00:00:03 200MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 672 prims, 1 key +00:00:03 200MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Curtains1/L/polySurface73: regular subdivision done - 1 iterations: 413 faces => 1652 quads - 0:00.00 +00:00:03 200MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/ChairB_1/Geom/polySurface32: regular subdivision done - 1 iterations: 104 faces => 416 quads - 0:00.00 +00:00:03 200MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/BookBlue_1/Geom/Book: regular subdivision done - 1 iterations: 668 faces => 2672 quads - 0:00.00 +00:00:03 200MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 200MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane278: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 200MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 352 prims, 1 key +00:00:03 200MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent36: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 200MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/pPlane105: regular subdivision done - 1 iterations: 120 faces => 480 quads - 0:00.00 +00:00:03 201MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/GarlicRope_1/Geom/pCylinder306: regular subdivision done - 1 iterations: 520 faces => 2000 quads - 0:00.00 +00:00:03 200MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 200MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 236 prims, 1 key +00:00:03 200MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/WallHinges/pSphere91: regular subdivision done - 1 iterations: 96 faces => 372 quads - 0:00.00 +00:00:03 200MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/PaperTowel/Towel_holder: regular subdivision done - 1 iterations: 340 faces => 1360 quads - 0:00.00 +00:00:03 200MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 200MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/GarlicRope_1/Geom/pCylinder308: regular subdivision done - 1 iterations: 520 faces => 2000 quads - 0:00.00 +00:00:03 200MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane362: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 200MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane192: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 201MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/StoolWooden_1/Geom/pCylinder191: regular subdivision done - 1 iterations: 390 faces => 1520 quads - 0:00.00 +00:00:03 200MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 24 prims, 1 key +00:00:03 201MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Doors/pCube14: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 201MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 200MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane233: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 202MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 201MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 520 prims, 1 key +00:00:03 200MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane222: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 201MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Windows_Frame/WindowBig/pCube362: regular subdivision done - 1 iterations: 94 faces => 376 quads - 0:00.00 +00:00:03 201MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Body/pCube331: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 201MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 3576 prims, 1 key +00:00:03 201MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/ChairB_2/Geom/polySurface29/polySurface87: regular subdivision done - 1 iterations: 236 faces => 944 quads - 0:00.00 +00:00:03 200MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2000 prims, 1 key +00:00:03 201MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/pPlane354: regular subdivision done - 1 iterations: 360 faces => 1440 quads - 0:00.00 +00:00:03 201MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group7/pCube371: regular subdivision done - 1 iterations: 216 faces => 864 quads - 0:00.00 +00:00:03 200MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube343: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 201MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2000 prims, 1 key +00:00:03 201MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1652 prims, 1 key +00:00:03 201MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/pPlane101: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 201MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/Strainer_1/Geom/pPlane88: regular subdivision done - 1 iterations: 251 faces => 1004 quads - 0:00.00 +00:00:03 202MB | [subdiv] /Kitchen_set/Props_grp/West_grp/WestWall_grp/FramePictureB_1/Geom/FramePicture: regular subdivision done - 1 iterations: 294 faces => 1176 quads - 0:00.00 +00:00:03 202MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 480 prims, 1 key +00:00:03 202MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 200MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 448 prims, 1 key +00:00:03 202MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1004 prims, 1 key +00:00:03 201MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2672 prims, 1 key +00:00:03 201MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 372 prims, 1 key +00:00:03 198MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 208 prims, 1 key +00:00:03 201MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2000 prims, 1 key +00:00:03 201MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 202MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane53: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 201MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1440 prims, 1 key +00:00:03 201MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/ChairB_1/Geom/pCylinder205: regular subdivision done - 1 iterations: 204 faces => 792 quads - 0:00.00 +00:00:03 201MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2000 prims, 1 key +00:00:03 201MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 201MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane176: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 201MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane234: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 201MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1520 prims, 1 key +00:00:03 201MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 201MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 416 prims, 1 key +00:00:03 201MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 376 prims, 1 key +00:00:03 201MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 202MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 944 prims, 1 key +00:00:03 202MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/AirVent/pPipe10: regular subdivision done - 1 iterations: 198 faces => 792 quads - 0:00.00 +00:00:03 202MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 864 prims, 1 key +00:00:03 200MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 202MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 201MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane287: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 202MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/GarlicRope_1/Geom/pCylinder248: regular subdivision done - 1 iterations: 440 faces => 1680 quads - 0:00.00 +00:00:03 202MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/pPlane95: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 201MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1360 prims, 1 key +00:00:03 202MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1176 prims, 1 key +00:00:03 202MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane200: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 202MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 202MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom2/pCylinder360: regular subdivision done - 1 iterations: 80 faces => 312 quads - 0:00.00 +00:00:03 202MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/GarlicRope_1/Geom/pCylinder250: regular subdivision done - 1 iterations: 520 faces => 2000 quads - 0:00.00 +00:00:03 201MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane46: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 203MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 203MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 792 prims, 1 key +00:00:03 203MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 203MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 203MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube354: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 202MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 203MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/KitchenTable_1/Geom/Legs/pCube190: regular subdivision done - 1 iterations: 6 faces => 24 quads - 0:00.00 +00:00:03 203MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 203MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder488: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 203MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane85: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 203MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/ChairB_2/Geom/pCylinder205: regular subdivision done - 1 iterations: 204 faces => 792 quads - 0:00.00 +00:00:03 203MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane244: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 203MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube308: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 203MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 792 prims, 1 key +00:00:03 205MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane60: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 202MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Windows_Frame/WindowBig/pCube335: regular subdivision done - 1 iterations: 110 faces => 440 quads - 0:00.00 +00:00:03 204MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 204MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group7/pCube375: regular subdivision done - 1 iterations: 214 faces => 856 quads - 0:00.00 +00:00:03 204MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube311: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 201MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 204MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane43: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 205MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 856 prims, 1 key +00:00:03 203MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane230: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 205MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1680 prims, 1 key +00:00:03 205MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 205MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/pPlane100: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 205MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder496: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 203MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/BookGreen_1/Geom/Book: regular subdivision done - 1 iterations: 668 faces => 2672 quads - 0:00.00 +00:00:03 205MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 205MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane175: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 205MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2000 prims, 1 key +00:00:03 205MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/GarlicRope_1/Geom/pCylinder309: regular subdivision done - 1 iterations: 520 faces => 2000 quads - 0:00.00 +00:00:03 205MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/GarlicRope_1/Geom/pCylinder279: regular subdivision done - 1 iterations: 520 faces => 2000 quads - 0:00.00 +00:00:03 205MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 24 prims, 1 key +00:00:03 205MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 202MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1440 prims, 1 key +00:00:03 205MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 205MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 205MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane67: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 205MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/CerealBoxB_2/Geom/CerealBox: regular subdivision done - 1 iterations: 1616 faces => 6464 quads - 0:00.00 +00:00:03 205MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 205MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 205MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/GarlicRope_1/Geom/pCylinder282: regular subdivision done - 1 iterations: 440 faces => 1680 quads - 0:00.00 +00:00:03 204MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube313: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 205MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 205MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 440 prims, 1 key +00:00:03 205MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane52: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 205MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Body/pCube278: regular subdivision done - 1 iterations: 62 faces => 248 quads - 0:00.00 +00:00:03 204MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 205MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 205MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 205MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 205MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 205MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/pPlane113: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 205MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallFruits_set/WallFlower_grp/WallFlower_1/Geom/pCylinder269: regular subdivision done - 1 iterations: 96 faces => 352 quads - 0:00.00 +00:00:03 205MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom2/pCylinder359: regular subdivision done - 1 iterations: 80 faces => 312 quads - 0:00.00 +00:00:03 205MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 205MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 205MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane253: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 205MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/PlateADirty_2/Geom/Plate: regular subdivision done - 1 iterations: 180 faces => 696 quads - 0:00.00 +00:00:03 205MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/GroceryBag: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 205MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2672 prims, 1 key +00:00:03 205MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder506: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 205MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2000 prims, 1 key +00:00:03 206MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Doors/pCube632: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 205MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 792 prims, 1 key +00:00:03 205MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group7/pCube396: regular subdivision done - 1 iterations: 168 faces => 672 quads - 0:00.00 +00:00:03 205MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder463: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 205MB | [subdiv] /Kitchen_set/Props_grp/West_grp/IronBoard_1/Geom/HandleIronBoard/polySurface78: regular subdivision done - 1 iterations: 110 faces => 420 quads - 0:00.00 +00:00:03 205MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Screws/pCube639: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 205MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane248: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 205MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/GarlicRope_1/Geom/pCylinder280: regular subdivision done - 1 iterations: 520 faces => 2000 quads - 0:00.00 +00:00:03 205MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane193: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1680 prims, 1 key +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 248 prims, 1 key +00:00:03 206MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/TeaKettle_1/Geom/polySurface1: regular subdivision done - 1 iterations: 220 faces => 860 quads - 0:00.00 +00:00:03 206MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/ChairB_2/Geom/pCylinder169: regular subdivision done - 1 iterations: 204 faces => 792 quads - 0:00.00 +00:00:03 206MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder499: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 206MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane84: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 206MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube317: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 203MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/StoolWooden_1/Geom/pCube364: regular subdivision done - 1 iterations: 60 faces => 236 quads - 0:00.00 +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 352 prims, 1 key +00:00:03 203MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/GarlicRope_1/Geom/pCylinder247: regular subdivision done - 1 iterations: 520 faces => 2000 quads - 0:00.00 +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 206MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane280: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 205MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2000 prims, 1 key +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 205MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 206MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane223: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 205MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 206MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group7/pCube397: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2000 prims, 1 key +00:00:03 206MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane215: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 420 prims, 1 key +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 672 prims, 1 key +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 205MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 206MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/pPlane394: regular subdivision done - 1 iterations: 50 faces => 200 quads - 0:00.00 +00:00:03 206MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane45: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 206MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane225: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 206MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent39: regular subdivision done - 1 iterations: 110 faces => 440 quads - 0:00.00 +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 792 prims, 1 key +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 860 prims, 1 key +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 207MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube389: regular subdivision done - 1 iterations: 148 faces => 592 quads - 0:00.00 +00:00:03 206MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube379: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 236 prims, 1 key +00:00:03 206MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane79: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 6464 prims, 1 key +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 206MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder511: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 206MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Body/pCube329: regular subdivision done - 1 iterations: 112 faces => 448 quads - 0:00.00 +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 206MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane71: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 205MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/BookTan_1/Geom/Book: regular subdivision done - 1 iterations: 668 faces => 2672 quads - 0:00.00 +00:00:03 206MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Doors/pCube630: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 206MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane68: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 206MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder497: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 206MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/Iron_1/Geom/pPlane340: regular subdivision done - 1 iterations: 198 faces => 792 quads - 0:00.00 +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 200 prims, 1 key +00:00:03 207MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/JarA_1/Geom/polySurface82: regular subdivision done - 1 iterations: 230 faces => 900 quads - 0:00.00 +00:00:03 207MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 207MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 696 prims, 1 key +00:00:03 207MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder505: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 207MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 440 prims, 1 key +00:00:03 206MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallFruits_set/WallOrange_grp/WallOrange_1/Geom/pCylinder270: regular subdivision done - 1 iterations: 80 faces => 288 quads - 0:00.00 +00:00:03 207MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane70: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 207MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 206MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane282: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 207MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Knobs/pCylinder144: regular subdivision done - 1 iterations: 252 faces => 984 quads - 0:00.00 +00:00:03 207MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 207MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/StoolWooden_1/Geom/pCube263: regular subdivision done - 1 iterations: 136 faces => 544 quads - 0:00.00 +00:00:03 207MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group7/pCube395: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 207MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 208MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder457: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 208MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Body/pCube241: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 208MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 448 prims, 1 key +00:00:03 208MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 206MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2000 prims, 1 key +00:00:03 209MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 209MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 209MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 209MB | [subdiv] /Kitchen_set/Props_grp/West_grp/IronBoard_1/Geom/HandleIronBoard1/polySurface78: regular subdivision done - 1 iterations: 110 faces => 420 quads - 0:00.00 +00:00:03 209MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2672 prims, 1 key +00:00:03 209MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 792 prims, 1 key +00:00:03 207MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom2/pCylinder365: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 209MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 209MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane265: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 209MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Windows_Frame/WindowBig/pCube337: regular subdivision done - 1 iterations: 110 faces => 440 quads - 0:00.00 +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/pCube415: regular subdivision done - 1 iterations: 168 faces => 672 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 288 prims, 1 key +00:00:03 210MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane301: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 210MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane55: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 206MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane281: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 210MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane48: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 210MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane178: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/CerealBoxB_1/Geom/CerealBox: regular subdivision done - 1 iterations: 1616 faces => 6464 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 984 prims, 1 key +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder510: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 544 prims, 1 key +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 208MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder464: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 207MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube376: regular subdivision done - 1 iterations: 236 faces => 944 quads - 0:00.00 +00:00:03 209MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 900 prims, 1 key +00:00:03 210MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Body/pCube286: regular subdivision done - 1 iterations: 108 faces => 432 quads - 0:00.00 +00:00:03 210MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane255: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 207MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 592 prims, 1 key +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder504: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/PaperTowelRoll_1/Geom/pPlane147: regular subdivision done - 1 iterations: 310 faces => 1240 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 440 prims, 1 key +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 672 prims, 1 key +00:00:03 208MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent16: regular subdivision done - 1 iterations: 410 faces => 1640 quads - 0:00.00 +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallFruits_set/WallBanana_grp/WallBanana_1/Geom/pPlane136: regular subdivision done - 1 iterations: 270 faces => 1080 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1080 prims, 1 key +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group7/pCube386: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/ChairB_1/Geom/pCylinder169: regular subdivision done - 1 iterations: 204 faces => 792 quads - 0:00.00 +00:00:03 210MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube340: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 210MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Curtains1/L/nurbsToPoly23: regular subdivision done - 1 iterations: 24 faces => 96 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 210MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane186: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 210MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane272: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 792 prims, 1 key +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/ChairB_1/Geom/polySurface29/polySurface87: regular subdivision done - 1 iterations: 236 faces => 944 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 420 prims, 1 key +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube372: regular subdivision done - 1 iterations: 148 faces => 592 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 432 prims, 1 key +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/JarA_1/Geom/pCylinder284: regular subdivision done - 1 iterations: 140 faces => 540 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 944 prims, 1 key +00:00:03 210MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane76: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom2/pCylinder367: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 210MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube352: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 210MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane238: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/West_grp/StoolMetalWire_1/Geom/Ball1/polySurface92: regular subdivision done - 1 iterations: 140 faces => 520 quads - 0:00.00 +00:00:03 210MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube348: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube394: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1240 prims, 1 key +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 6464 prims, 1 key +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1640 prims, 1 key +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallFruits_set/WallApples_grp/WallApple_1/Geom/pCylinder271: regular subdivision done - 1 iterations: 80 faces => 288 quads - 0:00.00 +00:00:03 210MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane297: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 210MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane56: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 96 prims, 1 key +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/GarlicRope_1/Geom/pCylinder394: regular subdivision done - 1 iterations: 520 faces => 2000 quads - 0:00.00 +00:00:03 210MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube345: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus309: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/BookGreen_2/Geom/Book: regular subdivision done - 1 iterations: 668 faces => 2672 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 944 prims, 1 key +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 540 prims, 1 key +00:00:03 210MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Sink/Faucet/pSphere11: regular subdivision done - 1 iterations: 680 faces => 2680 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder503: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 211MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane243: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/pPlane99: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 520 prims, 1 key +00:00:03 210MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane211: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 211MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Doors/pCube247: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/West_grp/BottleTall_1/Geom/Bottle: regular subdivision done - 1 iterations: 190 faces => 740 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 211MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2680 prims, 1 key +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 210MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent: regular subdivision done - 1 iterations: 248 faces => 992 quads - 0:00.00 +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder414: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 211MB | [subdiv] /Kitchen_set/Props_grp/West_grp/HangerLightBrown_1/Geom/pCube615: regular subdivision done - 1 iterations: 194 faces => 776 quads - 0:00.00 +00:00:03 210MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane59: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom/pCylinder358: regular subdivision done - 1 iterations: 104 faces => 400 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder470: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 592 prims, 1 key +00:00:03 212MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/PaperTowelRoll_1/Geom/polySurface23: regular subdivision done - 1 iterations: 300 faces => 1200 quads - 0:00.00 +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Leaf/pPlane135: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Knobs/pCylinder146: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/West_grp/WestWall_grp/FramePictureOval_1/Geom/FramePictureOval: regular subdivision done - 1 iterations: 180 faces => 680 quads - 0:00.00 +00:00:03 211MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 211MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 211MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2672 prims, 1 key +00:00:03 211MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 211MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 212MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 680 prims, 1 key +00:00:03 211MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/Strainer_1/Geom/pTorus162: regular subdivision done - 1 iterations: 112 faces => 448 quads - 0:00.00 +00:00:03 211MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/pPlane103: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 211MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 288 prims, 1 key +00:00:03 211MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane264: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 211MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Walls_Planks/Vent14: regular subdivision done - 1 iterations: 170 faces => 680 quads - 0:00.00 +00:00:03 212MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallFruits_set/WallApples_grp/WallApple_1/Geom/pPlane143: regular subdivision done - 1 iterations: 105 faces => 418 quads - 0:00.00 +00:00:03 211MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 211MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/GarlicRope_1/Geom/pCylinder312: regular subdivision done - 1 iterations: 520 faces => 2000 quads - 0:00.00 +00:00:03 211MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 740 prims, 1 key +00:00:03 211MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube391: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 211MB | [subdiv] /Kitchen_set/Props_grp/West_grp/StoolMetalWire_1/Geom/Ball1/polySurface91: regular subdivision done - 1 iterations: 380 faces => 1480 quads - 0:00.00 +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/CookingUtensils_grp/Whisk_1/Geom/pCylinder549: regular subdivision done - 1 iterations: 156 faces => 624 quads - 0:00.00 +00:00:03 212MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 212MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 212MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group7/pCube390: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 210MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Body/pCube295: regular subdivision done - 1 iterations: 112 faces => 448 quads - 0:00.00 +00:00:03 212MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 212MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 212MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder477: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2000 prims, 1 key +00:00:03 210MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 212MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1200 prims, 1 key +00:00:03 212MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 212MB | [subdiv] /Kitchen_set/Props_grp/West_grp/StoolMetalWire_1/Geom/chair_top_polySurface1: regular subdivision done - 1 iterations: 200 faces => 760 quads - 0:00.00 +00:00:03 212MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder423: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 212MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder428: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 212MB | [subdiv] /Kitchen_set/Props_grp/West_grp/WestWall_grp/PaperLarge_1/Geom/PaperLarge: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 211MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 212MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/pPlane393: regular subdivision done - 1 iterations: 50 faces => 200 quads - 0:00.00 +00:00:03 212MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 448 prims, 1 key +00:00:03 212MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane51: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 212MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/Iron_1/Geom/pPipe30: regular subdivision done - 1 iterations: 280 faces => 1120 quads - 0:00.00 +00:00:03 211MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/StoolWooden_1/Geom/pCylinder7: regular subdivision done - 1 iterations: 336 faces => 1304 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane269: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 210MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/StoolWooden_1/Geom/pCylinder192: regular subdivision done - 1 iterations: 316 faces => 1224 quads - 0:00.00 +00:00:03 212MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 680 prims, 1 key +00:00:03 212MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 992 prims, 1 key +00:00:03 212MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/pPlane384: regular subdivision done - 1 iterations: 25 faces => 100 quads - 0:00.00 +00:00:03 212MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 776 prims, 1 key +00:00:03 213MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2000 prims, 1 key +00:00:03 213MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder408: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 213MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/SpiceShaker_2/Geom/pCube628: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 213MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 624 prims, 1 key +00:00:03 212MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder489: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube165: regular subdivision done - 1 iterations: 6 faces => 24 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom/pCylinder364: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 448 prims, 1 key +00:00:03 211MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom2/pCylinder355: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Screws/pCylinder371: regular subdivision done - 1 iterations: 40 faces => 144 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Leaf/pPlane132: regular subdivision done - 1 iterations: 110 faces => 440 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube346: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 212MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group7/pCube392: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 760 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 212MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 200 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 212MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Outlet/Large/Outlet: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1120 prims, 1 key +00:00:03 212MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/Iron_1/Geom/pPlane338: regular subdivision done - 1 iterations: 72 faces => 288 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1304 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Windows_Frame/WindowBig/pCube361: regular subdivision done - 1 iterations: 94 faces => 376 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1480 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/TeaKettle_1/Geom/pTorus4: regular subdivision done - 1 iterations: 152 faces => 608 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube312: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/HangerLightBrownDirty_1/Geom/pCube615: regular subdivision done - 1 iterations: 194 faces => 776 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/Pineapple1: regular subdivision done - 1 iterations: 100 faces => 360 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder485: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane263: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group7/pCube387: regular subdivision done - 1 iterations: 216 faces => 864 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder518: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/GarlicRope_1/Geom/pCylinder277: regular subdivision done - 1 iterations: 520 faces => 2000 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder424: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 418 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder422: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/Letters/pPlane369: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group7/pCube372: regular subdivision done - 1 iterations: 148 faces => 592 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 288 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 376 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Doorknobs/pSphere50: regular subdivision done - 1 iterations: 252 faces => 984 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1224 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group7/pCube391: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/TableTop_grp/DinnerMat_1/Geom/DinnerMat: regular subdivision done - 1 iterations: 214 faces => 856 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/SpiceShaker_1/Geom/pCube628: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 608 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder462: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 24 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder490: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 144 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 776 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 360 prims, 1 key +00:00:03 212MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/HangerLightBrownDirty_3/Geom/pCube615: regular subdivision done - 1 iterations: 194 faces => 776 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/pPlane110: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 864 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom2/pCylinder366: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane267: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallFruits_set/WallFlower_grp/WallFlower_1/Geom/pPlane138: regular subdivision done - 1 iterations: 66 faces => 264 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group7/pCube389: regular subdivision done - 1 iterations: 148 faces => 592 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/pPlane115: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube375: regular subdivision done - 1 iterations: 214 faces => 856 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 592 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/WallHinges/pSphere61: regular subdivision done - 1 iterations: 96 faces => 372 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/West_grp/IronBoard_1/Geom/HandleIronBoard/polySurface79: regular subdivision done - 1 iterations: 110 faces => 420 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 984 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/BottleSmallGreen_1/Geom/pCylinder562: regular subdivision done - 1 iterations: 120 faces => 456 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group7/pCube394: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 456 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder471: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 856 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/Mixer_1/Geom/Handle/pCube473: regular subdivision done - 1 iterations: 318 faces => 1272 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube315: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom/pCylinder356: regular subdivision done - 1 iterations: 104 faces => 400 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/TeaKettle_1/Geom/Handle: regular subdivision done - 1 iterations: 240 faces => 960 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder491: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/OilBottle_1/Geom/pCylinder261: regular subdivision done - 1 iterations: 150 faces => 580 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder519: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/Letters/pPlane154: regular subdivision done - 1 iterations: 118 faces => 472 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 776 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 100 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Windows_Frame/WindowBig/pCube339: regular subdivision done - 1 iterations: 126 faces => 504 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/HangerLightBrown_2/Geom/pCube615: regular subdivision done - 1 iterations: 194 faces => 776 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Doorknobs/pSphere49: regular subdivision done - 1 iterations: 252 faces => 984 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 216MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 776 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder428: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 372 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 856 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/pPlane392: regular subdivision done - 1 iterations: 50 faces => 200 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 420 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder468: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/Letters/pPlane374: regular subdivision done - 1 iterations: 86 faces => 344 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 440 prims, 1 key +00:00:03 215MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1272 prims, 1 key +00:00:03 215MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 216MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane82: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 216MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 216MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 216MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 960 prims, 1 key +00:00:03 216MB | [subdiv] /Kitchen_set/Props_grp/West_grp/Ball_1/Geom/Ball: regular subdivision done - 1 iterations: 400 faces => 1560 quads - 0:00.00 +00:00:03 216MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 580 prims, 1 key +00:00:03 216MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 472 prims, 1 key +00:00:03 216MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube320: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 216MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/pPlane109: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 216MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom2/pCylinder363: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 216MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 504 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 592 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/BottleLargeGreen_1/Geom/pCylinder389: regular subdivision done - 1 iterations: 120 faces => 456 quads - 0:00.00 +00:00:03 217MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Leaf/pPlane134: regular subdivision done - 1 iterations: 80 faces => 320 quads - 0:00.00 +00:00:03 216MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/Letters/pPlane372: regular subdivision done - 1 iterations: 88 faces => 352 quads - 0:00.00 +00:00:03 216MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 216MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus324: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 216MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/HangerLightBrownDirty_2/Geom/pCube615: regular subdivision done - 1 iterations: 194 faces => 776 quads - 0:00.00 +00:00:03 216MB | [subdiv] /Kitchen_set/Props_grp/West_grp/IronBoard_1/Geom/IroningBoard/pCylinder326: regular subdivision done - 1 iterations: 163 faces => 634 quads - 0:00.00 +00:00:03 216MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 200 prims, 1 key +00:00:03 216MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/CupShelf/Shelf/pCube369: regular subdivision done - 1 iterations: 142 faces => 568 quads - 0:00.00 +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder450: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 216MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 216MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group7/pCube383: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 216MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/PotA_1/Geom/pCylinder315: regular subdivision done - 1 iterations: 240 faces => 940 quads - 0:00.00 +00:00:03 216MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Screws/pCylinder161: regular subdivision done - 1 iterations: 40 faces => 144 quads - 0:00.00 +00:00:03 216MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 344 prims, 1 key +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2000 prims, 1 key +00:00:03 216MB | [subdiv] /Kitchen_set/Props_grp/West_grp/IronBoard_1/Geom/IroningBoard/pPlane318: regular subdivision done - 1 iterations: 44 faces => 176 quads - 0:00.00 +00:00:03 216MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 216MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder513: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 216MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder469: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 216MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Fire_Stove/pCube253: regular subdivision done - 1 iterations: 654 faces => 2616 quads - 0:00.00 +00:00:03 216MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/pPlane353: regular subdivision done - 1 iterations: 25 faces => 100 quads - 0:00.00 +00:00:03 216MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 216MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube448: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 216MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder451: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 217MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/TopCabinetHinges/pPlane16: regular subdivision done - 1 iterations: 238 faces => 952 quads - 0:00.00 +00:00:03 217MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 218MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/OilBottle_1/Geom/pCube589: regular subdivision done - 1 iterations: 176 faces => 704 quads - 0:00.00 +00:00:03 217MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1560 prims, 1 key +00:00:03 216MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 984 prims, 1 key +00:00:03 217MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/BottleSmallBrown_1/Geom/pCylinder562: regular subdivision done - 1 iterations: 120 faces => 456 quads - 0:00.00 +00:00:03 217MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder422: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 217MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 320 prims, 1 key +00:00:03 216MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder461: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 217MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube386: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 217MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 634 prims, 1 key +00:00:03 216MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder491: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 217MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 217MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 568 prims, 1 key +00:00:03 214MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Knobs/pCylinder145: regular subdivision done - 1 iterations: 252 faces => 984 quads - 0:00.00 +00:00:03 217MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 940 prims, 1 key +00:00:03 217MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 216MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom/pCylinder363: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 217MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 144 prims, 1 key +00:00:03 218MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube397: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 217MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/Letters/pPlane386: regular subdivision done - 1 iterations: 88 faces => 352 quads - 0:00.00 +00:00:03 217MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/CookingUtensils_grp/Whisk_1/Geom/pCylinder544: regular subdivision done - 1 iterations: 156 faces => 624 quads - 0:00.00 +00:00:03 217MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 217MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 216MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/OilBottle_2/Geom/pCylinder261: regular subdivision done - 1 iterations: 150 faces => 580 quads - 0:00.00 +00:00:03 219MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/DustPan_1/Geom/DustPan: regular subdivision done - 1 iterations: 518 faces => 2074 quads - 0:00.00 +00:00:03 217MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/GarlicRope_1/Geom/pCylinder278: regular subdivision done - 1 iterations: 520 faces => 2000 quads - 0:00.00 +00:00:03 217MB | [subdiv] /Kitchen_set/Props_grp/Ceiling_grp/CeilingLight_1/Geom/pPipe2: regular subdivision done - 1 iterations: 180 faces => 720 quads - 0:00.00 +00:00:03 218MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 217MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 456 prims, 1 key +00:00:03 218MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 352 prims, 1 key +00:00:03 218MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 952 prims, 1 key +00:00:03 218MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder520: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 219MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2000 prims, 1 key +00:00:03 217MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 218MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2616 prims, 1 key +00:00:03 218MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 218MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom2/pCylinder361: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 217MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 776 prims, 1 key +00:00:03 218MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 218MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/PanA_1/Geom/polySurface81: regular subdivision done - 1 iterations: 320 faces => 1280 quads - 0:00.00 +00:00:03 219MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/TopCabinetHinges/pCylinder153: regular subdivision done - 1 iterations: 420 faces => 1640 quads - 0:00.00 +00:00:03 217MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/HangerLightBrown_3/Geom/pCube615: regular subdivision done - 1 iterations: 194 faces => 776 quads - 0:00.00 +00:00:03 218MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder446: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 218MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 218MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/GarlicRope_1/Geom/pCylinder249: regular subdivision done - 1 iterations: 520 faces => 2000 quads - 0:00.00 +00:00:03 218MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube543: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 218MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 218MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube417: regular subdivision done - 1 iterations: 96 faces => 384 quads - 0:00.00 +00:00:03 220MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 218MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube395: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 214MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 264 prims, 1 key +00:00:03 219MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/PotA_1/Geom/pCylinder314: regular subdivision done - 1 iterations: 205 faces => 800 quads - 0:00.00 +00:00:03 220MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallFruits_set/WallApples_grp/WallApple_1/Geom/pCylinder272: regular subdivision done - 1 iterations: 100 faces => 380 quads - 0:00.00 +00:00:03 217MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 100 prims, 1 key +00:00:03 219MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 624 prims, 1 key +00:00:03 219MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube86: regular subdivision done - 1 iterations: 96 faces => 384 quads - 0:00.00 +00:00:03 218MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 219MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Knobs/pCylinder142: regular subdivision done - 1 iterations: 252 faces => 984 quads - 0:00.00 +00:00:03 219MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 580 prims, 1 key +00:00:03 218MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 704 prims, 1 key +00:00:03 219MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 720 prims, 1 key +00:00:03 219MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube447: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 219MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 219MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube390: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 219MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/Letters/pPlane381: regular subdivision done - 1 iterations: 114 faces => 456 quads - 0:00.00 +00:00:03 219MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus323: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 218MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/WallHinges/pSphere76: regular subdivision done - 1 iterations: 96 faces => 372 quads - 0:00.00 +00:00:03 219MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 218MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 221MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 372 prims, 1 key +00:00:03 219MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Box_Stove/pCube210: regular subdivision done - 1 iterations: 170 faces => 680 quads - 0:00.00 +00:00:03 219MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/Iron_1/Geom/IronWire/pCube618: regular subdivision done - 1 iterations: 126 faces => 504 quads - 0:00.00 +00:00:03 221MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 456 prims, 1 key +00:00:03 221MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 680 prims, 1 key +00:00:03 220MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1280 prims, 1 key +00:00:03 220MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder485: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 220MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 220MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 776 prims, 1 key +00:00:03 218MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 984 prims, 1 key +00:00:03 220MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom1/pCylinder358: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 220MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 384 prims, 1 key +00:00:03 219MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 220MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 220MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube567: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 220MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2000 prims, 1 key +00:00:03 220MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 380 prims, 1 key +00:00:03 220MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/Letters/pPlane378: regular subdivision done - 1 iterations: 104 faces => 416 quads - 0:00.00 +00:00:03 219MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube402: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 220MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/CookingUtensils_grp/SpatulaSlotted_1/Geom/pPlane390: regular subdivision done - 1 iterations: 418 faces => 1664 quads - 0:00.00 +00:00:03 220MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 384 prims, 1 key +00:00:03 220MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder453: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 221MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/CookingUtensils_grp/Whisk_1/Geom/pCylinder547: regular subdivision done - 1 iterations: 156 faces => 624 quads - 0:00.00 +00:00:03 221MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Body/polySurface53: regular subdivision done - 1 iterations: 80 faces => 320 quads - 0:00.00 +00:00:03 221MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane262: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 221MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 984 prims, 1 key +00:00:03 221MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 221MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 221MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/BowlB_1/Geom/Bowl: regular subdivision done - 1 iterations: 260 faces => 1020 quads - 0:00.00 +00:00:03 221MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Doors/pCube634: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 221MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 217MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 176 prims, 1 key +00:00:03 221MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom2/pCylinder352: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 221MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/WallHinges/pSphere74: regular subdivision done - 1 iterations: 96 faces => 372 quads - 0:00.00 +00:00:03 221MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 504 prims, 1 key +00:00:03 219MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 352 prims, 1 key +00:00:03 221MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 221MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder445: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 221MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/AirVent/pCylinder167: regular subdivision done - 1 iterations: 120 faces => 460 quads - 0:00.00 +00:00:03 221MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube353: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 221MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 221MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Knobs/pCylinder128: regular subdivision done - 1 iterations: 252 faces => 984 quads - 0:00.00 +00:00:03 220MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 800 prims, 1 key +00:00:03 221MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 416 prims, 1 key +00:00:03 221MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube383: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 221MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder475: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 218MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 456 prims, 1 key +00:00:03 221MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/CupA_1/Geom/pTorus163: regular subdivision done - 1 iterations: 112 faces => 448 quads - 0:00.00 +00:00:03 221MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 221MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube100: regular subdivision done - 1 iterations: 96 faces => 384 quads - 0:00.00 +00:00:03 222MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Doors/pCube631: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 219MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2074 prims, 1 key +00:00:03 222MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1664 prims, 1 key +00:00:03 222MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 624 prims, 1 key +00:00:03 222MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 320 prims, 1 key +00:00:03 219MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Doors/pCube248: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 222MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Sink/SinkHole/pCylinder304: regular subdivision done - 1 iterations: 820 faces => 3200 quads - 0:00.00 +00:00:03 222MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/CookingUtensils_grp/Whisk_1/Geom/pCylinder546: regular subdivision done - 1 iterations: 156 faces => 624 quads - 0:00.00 +00:00:03 222MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube446: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 220MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1640 prims, 1 key +00:00:03 222MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group7/pCube378: regular subdivision done - 1 iterations: 216 faces => 864 quads - 0:00.00 +00:00:03 221MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube318: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 222MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 222MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Curtains1/CurtainRod: regular subdivision done - 1 iterations: 120 faces => 456 quads - 0:00.00 +00:00:03 222MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 222MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder482: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 222MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/WallHinges/pSphere65: regular subdivision done - 1 iterations: 96 faces => 372 quads - 0:00.00 +00:00:03 220MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube418: regular subdivision done - 1 iterations: 96 faces => 384 quads - 0:00.00 +00:00:03 222MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 222MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder471: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 221MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube419: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 222MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 222MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom1/pCylinder364: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 222MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 984 prims, 1 key +00:00:03 221MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 221MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder429: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 222MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 222MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 448 prims, 1 key +00:00:03 222MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 222MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 384 prims, 1 key +00:00:03 222MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/PlateAClean_2/Geom/Plate: regular subdivision done - 1 iterations: 180 faces => 696 quads - 0:00.00 +00:00:03 222MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 222MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder497: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 222MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 222MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 222MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder494: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 222MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 624 prims, 1 key +00:00:03 222MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/Mixer_1/Geom/Bowl/pSphere2: regular subdivision done - 1 iterations: 220 faces => 860 quads - 0:00.00 +00:00:03 222MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Body/pCube292: regular subdivision done - 1 iterations: 112 faces => 448 quads - 0:00.00 +00:00:03 222MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1020 prims, 1 key +00:00:03 222MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 222MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 372 prims, 1 key +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 860 prims, 1 key +00:00:03 222MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom2/pCylinder357: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 222MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 456 prims, 1 key +00:00:03 222MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Windows_Frame/WindowBig/pCube358: regular subdivision done - 1 iterations: 94 faces => 376 quads - 0:00.00 +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 372 prims, 1 key +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 3200 prims, 1 key +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 384 prims, 1 key +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder425: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 222MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 460 prims, 1 key +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 222MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group7/pCube398: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Knobs/pCylinder129: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube541: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 222MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/Iron_1/Geom/pCylinder348: regular subdivision done - 1 iterations: 120 faces => 460 quads - 0:00.00 +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder443: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 222MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/OilBottle_2/Geom/pCube589: regular subdivision done - 1 iterations: 176 faces => 704 quads - 0:00.00 +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group7/pCube381: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 222MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder533: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/PlateA_1/Geom/Plate: regular subdivision done - 1 iterations: 180 faces => 696 quads - 0:00.00 +00:00:03 222MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 864 prims, 1 key +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/Magnet/pCube620: regular subdivision done - 1 iterations: 164 faces => 656 quads - 0:00.00 +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/CookingUtensils_grp/Whisk_1/Geom/pCylinder545: regular subdivision done - 1 iterations: 156 faces => 624 quads - 0:00.00 +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 448 prims, 1 key +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder462: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 223MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/TopCabinetHinges/pPlane342: regular subdivision done - 1 iterations: 238 faces => 952 quads - 0:00.00 +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 376 prims, 1 key +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube456: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 223MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/WallHinges/pSphere72: regular subdivision done - 1 iterations: 96 faces => 372 quads - 0:00.00 +00:00:03 223MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Sink/SinkHole/pCylinder303: regular subdivision done - 1 iterations: 200 faces => 760 quads - 0:00.00 +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 952 prims, 1 key +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/Mixer_1/Geom/Body/pSphere80: regular subdivision done - 1 iterations: 120 faces => 468 quads - 0:00.00 +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube398: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallFruits_set/WallFlower_grp/WallFlower_1/Geom/pPlane140: regular subdivision done - 1 iterations: 66 faces => 264 quads - 0:00.00 +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder435: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 696 prims, 1 key +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder496: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/HangerLightBrown_2/Geom/pCylinder316: regular subdivision done - 1 iterations: 170 faces => 660 quads - 0:00.00 +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 704 prims, 1 key +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/SaltShaker_1/Geom/pCylinder266: regular subdivision done - 1 iterations: 180 faces => 700 quads - 0:00.00 +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/pPlane108: regular subdivision done - 1 iterations: 50 faces => 200 quads - 0:00.00 +00:00:03 223MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/WallHinges/pSphere78: regular subdivision done - 1 iterations: 96 faces => 372 quads - 0:00.00 +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 656 prims, 1 key +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group7/pCube374: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder483: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 700 prims, 1 key +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/Magnet/pCube619: regular subdivision done - 1 iterations: 38 faces => 152 quads - 0:00.00 +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/PlateAClean_1/Geom/Plate: regular subdivision done - 1 iterations: 180 faces => 696 quads - 0:00.00 +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/CookingUtensils_grp/Whisk_1/Geom/pCylinder548: regular subdivision done - 1 iterations: 156 faces => 624 quads - 0:00.00 +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Handles/pCube259: regular subdivision done - 1 iterations: 86 faces => 344 quads - 0:00.00 +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder477: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/CastIron_1/Geom/pTorus1: regular subdivision done - 1 iterations: 112 faces => 448 quads - 0:00.00 +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder413: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 223MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/WallHinges/pSphere92: regular subdivision done - 1 iterations: 96 faces => 372 quads - 0:00.00 +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/West_grp/SteamCooker_1/Geom/pCylinder56: regular subdivision done - 1 iterations: 360 faces => 1400 quads - 0:00.00 +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 460 prims, 1 key +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Screws/pCylinder373: regular subdivision done - 1 iterations: 40 faces => 144 quads - 0:00.00 +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/Mixer_1/Geom/Handle/pCylinder216: regular subdivision done - 1 iterations: 96 faces => 360 quads - 0:00.00 +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/JarB_1/Geom/pSphere95: regular subdivision done - 1 iterations: 252 faces => 984 quads - 0:00.00 +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 223MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/TopCabinetHinges/pCylinder368: regular subdivision done - 1 iterations: 420 faces => 1640 quads - 0:00.00 +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube94: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube542: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder532: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 660 prims, 1 key +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 696 prims, 1 key +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 624 prims, 1 key +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 372 prims, 1 key +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom2/pCylinder364: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 224MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 224MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group7/pCube382: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 224MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/SaltShakerShakerPepper_1/Geom/pCylinder266: regular subdivision done - 1 iterations: 180 faces => 700 quads - 0:00.00 +00:00:03 224MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 624 prims, 1 key +00:00:03 226MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 760 prims, 1 key +00:00:03 224MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 696 prims, 1 key +00:00:03 226MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 372 prims, 1 key +00:00:03 224MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 224MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/PlateA_2/Geom/Plate: regular subdivision done - 1 iterations: 180 faces => 696 quads - 0:00.00 +00:00:03 226MB | [subdiv] /Kitchen_set/Props_grp/West_grp/IronBoard_1/Geom/IroningBoard/pPlane326: regular subdivision done - 1 iterations: 46 faces => 184 quads - 0:00.00 +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 468 prims, 1 key +00:00:03 224MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 372 prims, 1 key +00:00:03 224MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 448 prims, 1 key +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 264 prims, 1 key +00:00:03 224MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube455: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 225MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 144 prims, 1 key +00:00:03 225MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube393: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 225MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1400 prims, 1 key +00:00:03 226MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 360 prims, 1 key +00:00:03 226MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube378: regular subdivision done - 1 iterations: 216 faces => 864 quads - 0:00.00 +00:00:03 226MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/PlateA_3/Geom/Plate: regular subdivision done - 1 iterations: 180 faces => 696 quads - 0:00.00 +00:00:03 226MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 226MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 984 prims, 1 key +00:00:03 227MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/MeasuringCup_1/Geom/MeasuringCup: regular subdivision done - 1 iterations: 219 faces => 854 quads - 0:00.00 +00:00:03 226MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/Letters/pPlane382: regular subdivision done - 1 iterations: 104 faces => 416 quads - 0:00.00 +00:00:03 226MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 226MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1640 prims, 1 key +00:00:03 224MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 152 prims, 1 key +00:00:03 226MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/HangerLightBrownDirty_1/Geom/pCylinder316: regular subdivision done - 1 iterations: 170 faces => 660 quads - 0:00.00 +00:00:03 226MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 226MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/WallHinges/pSphere60: regular subdivision done - 1 iterations: 96 faces => 372 quads - 0:00.00 +00:00:03 224MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder468: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 226MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/pPlane112: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 226MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder453: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 226MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 700 prims, 1 key +00:00:03 224MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 344 prims, 1 key +00:00:03 226MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 184 prims, 1 key +00:00:03 226MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/Letters/pPlane380: regular subdivision done - 1 iterations: 96 faces => 384 quads - 0:00.00 +00:00:03 228MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/SpiceShaker_2/Geom/pCylinder384: regular subdivision done - 1 iterations: 200 faces => 780 quads - 0:00.00 +00:00:03 223MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder448: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 226MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/CastIron_1/Geom/pTorus341: regular subdivision done - 1 iterations: 112 faces => 448 quads - 0:00.00 +00:00:03 227MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 228MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 448 prims, 1 key +00:00:03 227MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/CupShelf/Shelf/Rings/pCube408: regular subdivision done - 1 iterations: 136 faces => 544 quads - 0:00.00 +00:00:03 223MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 200 prims, 1 key +00:00:03 227MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 227MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube396: regular subdivision done - 1 iterations: 168 faces => 672 quads - 0:00.00 +00:00:03 226MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 227MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 864 prims, 1 key +00:00:03 227MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Sink/Faucet/pCylinder66: regular subdivision done - 1 iterations: 680 faces => 2640 quads - 0:00.00 +00:00:03 228MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Handles/pCylinder133: regular subdivision done - 1 iterations: 112 faces => 432 quads - 0:00.00 +00:00:03 228MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 416 prims, 1 key +00:00:03 226MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 228MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 854 prims, 1 key +00:00:03 228MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder414: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 226MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom/pCylinder354: regular subdivision done - 1 iterations: 104 faces => 400 quads - 0:00.00 +00:00:03 228MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 228MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Windows_Frame/WindowStill/Window_Frame_Arch/pCube156: regular subdivision done - 1 iterations: 38 faces => 152 quads - 0:00.00 +00:00:03 224MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 228MB | [subdiv] /Kitchen_set/Props_grp/West_grp/ShellLarge_1/Geom/Geom: regular subdivision done - 1 iterations: 1204 faces => 4740 quads - 0:00.00 +00:00:03 228MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2640 prims, 1 key +00:00:03 228MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 228MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 228MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Doorknobs/pSphere48: regular subdivision done - 1 iterations: 252 faces => 984 quads - 0:00.00 +00:00:03 226MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 696 prims, 1 key +00:00:03 228MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom/pCylinder357: regular subdivision done - 1 iterations: 104 faces => 400 quads - 0:00.00 +00:00:03 228MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/TopCabinetHinges/pPlane18: regular subdivision done - 1 iterations: 238 faces => 952 quads - 0:00.00 +00:00:03 228MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/Letters/pPlane157: regular subdivision done - 1 iterations: 86 faces => 344 quads - 0:00.00 +00:00:03 228MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 228MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 696 prims, 1 key +00:00:03 228MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 780 prims, 1 key +00:00:03 228MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/TopCabinetHinges/pPlane397: regular subdivision done - 1 iterations: 238 faces => 952 quads - 0:00.00 +00:00:03 228MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 544 prims, 1 key +00:00:03 228MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder417: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 228MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder486: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 228MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube454: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 228MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube131: regular subdivision done - 1 iterations: 148 faces => 592 quads - 0:00.00 +00:00:03 228MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 672 prims, 1 key +00:00:03 228MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 660 prims, 1 key +00:00:03 228MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube559: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 228MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube381: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 228MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 432 prims, 1 key +00:00:03 228MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube399: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 228MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 372 prims, 1 key +00:00:03 228MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 228MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder512: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 228MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 152 prims, 1 key +00:00:03 228MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus312: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 228MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 384 prims, 1 key +00:00:03 227MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/WallHinges/pSphere62: regular subdivision done - 1 iterations: 96 faces => 372 quads - 0:00.00 +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 984 prims, 1 key +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 229MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Doorknobs/pSphere29: regular subdivision done - 1 iterations: 252 faces => 984 quads - 0:00.00 +00:00:03 229MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Sink/Faucet/polySurface74: regular subdivision done - 1 iterations: 252 faces => 988 quads - 0:00.00 +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube420: regular subdivision done - 1 iterations: 170 faces => 680 quads - 0:00.00 +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 952 prims, 1 key +00:00:03 228MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/PlateADirty_1/Geom/Plate: regular subdivision done - 1 iterations: 180 faces => 696 quads - 0:00.00 +00:00:03 229MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Body/pCube293: regular subdivision done - 1 iterations: 112 faces => 448 quads - 0:00.00 +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 227MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/WallHinges/pSphere69: regular subdivision done - 1 iterations: 96 faces => 372 quads - 0:00.00 +00:00:03 229MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/CupShelf/Shelf/pCube365: regular subdivision done - 1 iterations: 142 faces => 568 quads - 0:00.00 +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 4740 prims, 1 key +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 228MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom2/pCylinder356: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 228MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/CupB_1/Geom/Cup: regular subdivision done - 1 iterations: 280 faces => 1096 quads - 0:00.00 +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/West_grp/HangerLightBrown_1/Geom/pCylinder316: regular subdivision done - 1 iterations: 170 faces => 660 quads - 0:00.00 +00:00:03 228MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus287: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/BowlF_3/Geom/Bowl: regular subdivision done - 1 iterations: 480 faces => 1880 quads - 0:00.00 +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Handles/pCylinder136: regular subdivision done - 1 iterations: 112 faces => 432 quads - 0:00.00 +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder433: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 227MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/BottleLargeGreen_1/Geom/pCylinder390: regular subdivision done - 1 iterations: 180 faces => 700 quads - 0:00.00 +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 372 prims, 1 key +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/AirVent/Fan/pCylinder556: regular subdivision done - 1 iterations: 72 faces => 272 quads - 0:00.00 +00:00:03 229MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/TopCabinetHinges/pPlane343: regular subdivision done - 1 iterations: 238 faces => 952 quads - 0:00.00 +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 344 prims, 1 key +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom/pCylinder365: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 988 prims, 1 key +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 984 prims, 1 key +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder467: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 696 prims, 1 key +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 952 prims, 1 key +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder416: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 372 prims, 1 key +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 592 prims, 1 key +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder487: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/BowlC_1/Geom/Bowl: regular subdivision done - 1 iterations: 340 faces => 1320 quads - 0:00.00 +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube453: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube588: regular subdivision done - 1 iterations: 86 faces => 350 quads - 0:00.00 +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/BottleSmallGreen_1/Geom/pCylinder559: regular subdivision done - 1 iterations: 180 faces => 700 quads - 0:00.00 +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/Toaster_1/Geom/Cable/pCylinder399: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder408: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom/pCylinder366: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder506: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder454: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus311: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/SpiceShaker_1/Geom/pCylinder384: regular subdivision done - 1 iterations: 200 faces => 780 quads - 0:00.00 +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 272 prims, 1 key +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 680 prims, 1 key +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 952 prims, 1 key +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder455: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 448 prims, 1 key +00:00:03 229MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/WallHinges/Hook/pCylinder291: regular subdivision done - 1 iterations: 132 faces => 504 quads - 0:00.00 +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 568 prims, 1 key +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/Mixer_1/Geom/Body/pCube191: regular subdivision done - 1 iterations: 220 faces => 880 quads - 0:00.00 +00:00:03 229MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Doorknobs/pSphere45: regular subdivision done - 1 iterations: 252 faces => 984 quads - 0:00.00 +00:00:03 231MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 880 prims, 1 key +00:00:03 231MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/CupShelf/Shelf/Rings/pCube409: regular subdivision done - 1 iterations: 136 faces => 544 quads - 0:00.00 +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 660 prims, 1 key +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/pPlane385: regular subdivision done - 1 iterations: 25 faces => 100 quads - 0:00.00 +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1096 prims, 1 key +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom2/pCylinder362: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/Strainer_1/Geom/pTorus3: regular subdivision done - 1 iterations: 112 faces => 448 quads - 0:00.00 +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 230MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/SoapDispenser_1/Geom/Cap/pCylinder68: regular subdivision done - 1 iterations: 360 faces => 1420 quads - 0:00.00 +00:00:03 230MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1320 prims, 1 key +00:00:03 230MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 350 prims, 1 key +00:00:03 231MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus323: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 232MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 231MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 231MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 231MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 700 prims, 1 key +00:00:03 231MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder449: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 700 prims, 1 key +00:00:03 231MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 231MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder434: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 231MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 231MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/AirVent/Fan/pCylinder555: regular subdivision done - 1 iterations: 72 faces => 272 quads - 0:00.00 +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 231MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 231MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder418: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 231MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder481: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 231MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 544 prims, 1 key +00:00:03 229MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 231MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/HangerLightBrown_3/Geom/pCylinder316: regular subdivision done - 1 iterations: 170 faces => 660 quads - 0:00.00 +00:00:03 231MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 984 prims, 1 key +00:00:03 231MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 229MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube374: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 231MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Doors/pCube250: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 231MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 432 prims, 1 key +00:00:03 231MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/CupD_2/Geom/Cup: regular subdivision done - 1 iterations: 328 faces => 1288 quads - 0:00.00 +00:00:03 231MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1420 prims, 1 key +00:00:03 231MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder457: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 231MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/West_grp/IronBoard_1/Geom/HandleIronBoard/pPipe29: regular subdivision done - 1 iterations: 160 faces => 640 quads - 0:00.00 +00:00:03 232MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/BowlA_2/Geom/Bowl: regular subdivision done - 1 iterations: 380 faces => 1480 quads - 0:00.00 +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom/pCylinder355: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/BottleSmallBrown_1/Geom/pCylinder559: regular subdivision done - 1 iterations: 180 faces => 700 quads - 0:00.00 +00:00:03 232MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder512: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/Toaster_1/Geom/Body/Body: regular subdivision done - 1 iterations: 441 faces => 1764 quads - 0:00.00 +00:00:03 231MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 504 prims, 1 key +00:00:03 232MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 272 prims, 1 key +00:00:03 231MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 100 prims, 1 key +00:00:03 232MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 232MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube429: regular subdivision done - 1 iterations: 210 faces => 840 quads - 0:00.00 +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder442: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/Letters/pPlane375: regular subdivision done - 1 iterations: 158 faces => 632 quads - 0:00.00 +00:00:03 232MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1880 prims, 1 key +00:00:03 232MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 660 prims, 1 key +00:00:03 231MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube377: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder436: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 232MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 232MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 232MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder455: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/BowlF_2/Geom/Bowl: regular subdivision done - 1 iterations: 480 faces => 1880 quads - 0:00.00 +00:00:03 232MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1288 prims, 1 key +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder492: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder420: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus319: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder465: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 232MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 234MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/CupD_1/Geom/Cup: regular subdivision done - 1 iterations: 328 faces => 1288 quads - 0:00.00 +00:00:03 232MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 700 prims, 1 key +00:00:03 232MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom/pCylinder534: regular subdivision done - 1 iterations: 104 faces => 400 quads - 0:00.00 +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/Toaster_1/Geom/PlasticPieces/pCube145: regular subdivision done - 1 iterations: 54 faces => 216 quads - 0:00.00 +00:00:03 231MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 448 prims, 1 key +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder413: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 232MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 840 prims, 1 key +00:00:03 232MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1764 prims, 1 key +00:00:03 232MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 232MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 632 prims, 1 key +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Monitor/pCube204: regular subdivision done - 1 iterations: 160 faces => 640 quads - 0:00.00 +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube580: regular subdivision done - 1 iterations: 86 faces => 350 quads - 0:00.00 +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube102: regular subdivision done - 1 iterations: 210 faces => 840 quads - 0:00.00 +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group7/pCube373: regular subdivision done - 1 iterations: 214 faces => 856 quads - 0:00.00 +00:00:03 232MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/HangerLightBrownDirty_2/Geom/pCylinder316: regular subdivision done - 1 iterations: 170 faces => 660 quads - 0:00.00 +00:00:03 232MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/Magnet/pCylinder374: regular subdivision done - 1 iterations: 40 faces => 144 quads - 0:00.00 +00:00:03 232MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/WallHinges/pSphere67: regular subdivision done - 1 iterations: 96 faces => 372 quads - 0:00.00 +00:00:03 232MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube392: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 233MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 233MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1880 prims, 1 key +00:00:03 234MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 232MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/WallHinges/pSphere71: regular subdivision done - 1 iterations: 96 faces => 372 quads - 0:00.00 +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder466: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/TeaKettle_1/Geom/pCylinder157: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Fire_Stove/pCube218: regular subdivision done - 1 iterations: 654 faces => 2616 quads - 0:00.00 +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/BottleLargeRose_1/Geom/pCylinder390: regular subdivision done - 1 iterations: 180 faces => 700 quads - 0:00.00 +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube114: regular subdivision done - 1 iterations: 170 faces => 680 quads - 0:00.00 +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1288 prims, 1 key +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/BowlF_1/Geom/Bowl: regular subdivision done - 1 iterations: 480 faces => 1880 quads - 0:00.00 +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group7/pCube385: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/AirVent/pCylinder165: regular subdivision done - 1 iterations: 120 faces => 460 quads - 0:00.00 +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 640 prims, 1 key +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 350 prims, 1 key +00:00:03 232MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 640 prims, 1 key +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 840 prims, 1 key +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 856 prims, 1 key +00:00:03 235MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Sink/Faucet/polySurface76: regular subdivision done - 1 iterations: 252 faces => 988 quads - 0:00.00 +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 660 prims, 1 key +00:00:03 232MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1480 prims, 1 key +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/Magnet/pCylinder375: regular subdivision done - 1 iterations: 48 faces => 176 quads - 0:00.00 +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 144 prims, 1 key +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 372 prims, 1 key +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 988 prims, 1 key +00:00:03 234MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder478: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/Mixer_1/Geom/Mixer/pCylinder257: regular subdivision done - 1 iterations: 84 faces => 312 quads - 0:00.00 +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder517: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube382: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus325: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 372 prims, 1 key +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 216 prims, 1 key +00:00:03 232MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder495: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 700 prims, 1 key +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Box_Stove/pCube416: regular subdivision done - 1 iterations: 166 faces => 664 quads - 0:00.00 +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 680 prims, 1 key +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/TeaKettle_1/Geom/polySurface2: regular subdivision done - 1 iterations: 250 faces => 980 quads - 0:00.00 +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 664 prims, 1 key +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 460 prims, 1 key +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 235MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/CupShelf/Shelf/Rings/pCube404: regular subdivision done - 1 iterations: 136 faces => 544 quads - 0:00.00 +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2616 prims, 1 key +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube387: regular subdivision done - 1 iterations: 216 faces => 864 quads - 0:00.00 +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1880 prims, 1 key +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube426: regular subdivision done - 1 iterations: 210 faces => 840 quads - 0:00.00 +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube581: regular subdivision done - 1 iterations: 192 faces => 780 quads - 0:00.00 +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube545: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder436: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom/pCylinder367: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/HangerLightBrownDirty_3/Geom/pCylinder316: regular subdivision done - 1 iterations: 170 faces => 660 quads - 0:00.00 +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/BowlA_3/Geom/Bowl: regular subdivision done - 1 iterations: 380 faces => 1480 quads - 0:00.00 +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 235MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Outlet/Small/Outlet1: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder530: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder419: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder412: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/Letters/pPlane379: regular subdivision done - 1 iterations: 128 faces => 512 quads - 0:00.00 +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 231MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 780 prims, 1 key +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube388: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder458: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 980 prims, 1 key +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 544 prims, 1 key +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group7/pCube376: regular subdivision done - 1 iterations: 236 faces => 944 quads - 0:00.00 +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube424: regular subdivision done - 1 iterations: 210 faces => 840 quads - 0:00.00 +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 864 prims, 1 key +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder531: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 236MB | 0% done - 19 rays/pixel +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 840 prims, 1 key +00:00:03 236MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 840 prims, 1 key +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 780 prims, 1 key +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom/pCylinder352: regular subdivision done - 1 iterations: 104 faces => 400 quads - 0:00.00 +00:00:03 236MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube529: regular subdivision done - 1 iterations: 192 faces => 780 quads - 0:00.00 +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 660 prims, 1 key +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder498: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 236MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 780 prims, 1 key +00:00:03 236MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1480 prims, 1 key +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/West_grp/IronBoard_1/Geom/HandleIronBoard1/pPipe29: regular subdivision done - 1 iterations: 160 faces => 640 quads - 0:00.00 +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 176 prims, 1 key +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/Toaster_1/Geom/Cable/pCube617: regular subdivision done - 1 iterations: 126 faces => 504 quads - 0:00.00 +00:00:03 236MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/TileFloor/pPlane66: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 512 prims, 1 key +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/BowlA_1/Geom/Bowl: regular subdivision done - 1 iterations: 380 faces => 1480 quads - 0:00.00 +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder447: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 235MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/WallHinges/pSphere75: regular subdivision done - 1 iterations: 96 faces => 372 quads - 0:00.00 +00:00:03 235MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Curtains1/CurtainHolderLeft/pTorus160: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 236MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 236MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Walls/Wall_Structure/pCube316: regular subdivision done - 1 iterations: 78 faces => 312 quads - 0:00.00 +00:00:03 236MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube385: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 236MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Leaf/pPlane131: regular subdivision done - 1 iterations: 126 faces => 504 quads - 0:00.00 +00:00:03 236MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder429: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 236MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube425: regular subdivision done - 1 iterations: 210 faces => 840 quads - 0:00.00 +00:00:03 236MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Doorknobs/pSphere33: regular subdivision done - 1 iterations: 252 faces => 984 quads - 0:00.00 +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 236MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 236MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Fire_Stove/pCube252: regular subdivision done - 1 iterations: 654 faces => 2616 quads - 0:00.00 +00:00:03 235MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 236MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallFruits_set/WallFlower_grp/WallFlower_1/Geom/pPlane139: regular subdivision done - 1 iterations: 66 faces => 264 quads - 0:00.00 +00:00:03 236MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube566: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 236MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 640 prims, 1 key +00:00:03 236MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/TopCabinetHinges/pCylinder155: regular subdivision done - 1 iterations: 420 faces => 1640 quads - 0:00.00 +00:00:03 236MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/WallHinges/Hook/pCylinder292: regular subdivision done - 1 iterations: 108 faces => 414 quads - 0:00.00 +00:00:03 236MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder454: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 237MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Sink/Faucet/pCylinder71: regular subdivision done - 1 iterations: 60 faces => 200 quads - 0:00.00 +00:00:03 237MB | [subdiv] /Kitchen_set/Props_grp/West_grp/WestWall_grp/FramePictureD_1/Geom/FramePicture: regular subdivision done - 1 iterations: 316 faces => 1264 quads - 0:00.00 +00:00:03 237MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 504 prims, 1 key +00:00:03 237MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom2/pCylinder358: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 236MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 944 prims, 1 key +00:00:03 238MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 238MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder459: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder484: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 238MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1480 prims, 1 key +00:00:03 238MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 236MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom2/pCylinder353: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 238MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder421: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 238MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 504 prims, 1 key +00:00:03 238MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 236MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube557: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 238MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/TableTop_grp/CerealBowl_grp/BowlD_1/Geom/Bowl: regular subdivision done - 1 iterations: 336 faces => 1316 quads - 0:00.00 +00:00:03 238MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 840 prims, 1 key +00:00:03 236MB | [subdiv] /Kitchen_set/Props_grp/West_grp/IronBoard_1/Geom/HandleIronBoard1/polySurface94: regular subdivision done - 1 iterations: 110 faces => 420 quads - 0:00.00 +00:00:03 238MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 984 prims, 1 key +00:00:03 238MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom/pCylinder361: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 236MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallFruits_set/WallOrange_grp/WallOrange_1/Geom/pPlane141: regular subdivision done - 1 iterations: 66 faces => 264 quads - 0:00.00 +00:00:03 238MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder456: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 238MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 235MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group6/pCube380: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 238MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 414 prims, 1 key +00:00:03 238MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder412: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 237MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 239MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 200 prims, 1 key +00:00:03 239MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 239MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Screws/pCube203: regular subdivision done - 1 iterations: 580 faces => 2320 quads - 0:00.00 +00:00:03 238MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 372 prims, 1 key +00:00:03 239MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 239MB | [subdiv] /Kitchen_set/Props_grp/West_grp/IronBoard_1/Geom/IroningBoard/pPlane316: regular subdivision done - 1 iterations: 44 faces => 176 quads - 0:00.00 +00:00:03 239MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1264 prims, 1 key +00:00:03 239MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 239MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 239MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder415: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 238MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube449: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 239MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 239MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 238MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 239MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 239MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 420 prims, 1 key +00:00:03 239MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/WallHinges/pSphere68: regular subdivision done - 1 iterations: 96 faces => 372 quads - 0:00.00 +00:00:03 239MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube640: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 238MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 264 prims, 1 key +00:00:03 239MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 264 prims, 1 key +00:00:03 239MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 239MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube451: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 238MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2616 prims, 1 key +00:00:03 239MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 239MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1640 prims, 1 key +00:00:03 239MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 239MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube583: regular subdivision done - 1 iterations: 192 faces => 780 quads - 0:00.00 +00:00:03 239MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Sink/Faucet/pSphere86: regular subdivision done - 1 iterations: 96 faces => 372 quads - 0:00.00 +00:00:03 238MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 239MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 176 prims, 1 key +00:00:03 239MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus299: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 239MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/WallHinges/pSphere73: regular subdivision done - 1 iterations: 96 faces => 372 quads - 0:00.00 +00:00:03 239MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder448: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 239MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group7/pCube388: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 239MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 239MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus302: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 238MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Sink/SinkHole/pPipe25: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 239MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 239MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom1/pCylinder352: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 239MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder415: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 239MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1316 prims, 1 key +00:00:03 239MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder490: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 239MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder443: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 239MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/AirVent/pCylinder166: regular subdivision done - 1 iterations: 120 faces => 460 quads - 0:00.00 +00:00:03 239MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 239MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube546: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 239MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallFruits_set/WallOrange_grp/WallOrange_1/Geom/pPlane142: regular subdivision done - 1 iterations: 66 faces => 264 quads - 0:00.00 +00:00:03 239MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 239MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder441: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 239MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder410: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 239MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom1/pCylinder367: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 240MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 372 prims, 1 key +00:00:03 240MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/TopCabinetHinges/pCylinder558: regular subdivision done - 1 iterations: 420 faces => 1640 quads - 0:00.00 +00:00:03 240MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Outlet/Large/pCube460: regular subdivision done - 1 iterations: 343 faces => 1378 quads - 0:00.00 +00:00:03 240MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/TopCabinetHinges/pPlane19: regular subdivision done - 1 iterations: 238 faces => 952 quads - 0:00.00 +00:00:03 239MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/WallHinges/pSphere77: regular subdivision done - 1 iterations: 96 faces => 372 quads - 0:00.00 +00:00:03 240MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Curtains1/CurtainHolderLeft/pTorus161: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 240MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 372 prims, 1 key +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1640 prims, 1 key +00:00:03 239MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2320 prims, 1 key +00:00:03 241MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 241MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder421: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 241MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 241MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 241MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Fire_Stove/pCube254: regular subdivision done - 1 iterations: 654 faces => 2616 quads - 0:00.00 +00:00:03 239MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder526: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 241MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 241MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom1/pCylinder356: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 241MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube450: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 241MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 241MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 239MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 241MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 241MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/FlowerPotB_1/Geom/FlowerPot: regular subdivision done - 1 iterations: 280 faces => 1080 quads - 0:00.00 +00:00:03 239MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/SpiceBox_2/Geom/pCube636: regular subdivision done - 1 iterations: 214 faces => 856 quads - 0:00.00 +00:00:03 241MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube582: regular subdivision done - 1 iterations: 192 faces => 780 quads - 0:00.00 +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 856 prims, 1 key +00:00:03 241MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 240MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder469: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 241MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 240MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 780 prims, 1 key +00:00:03 241MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 240MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1378 prims, 1 key +00:00:03 241MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Outlet/Small/pCube596: regular subdivision done - 1 iterations: 343 faces => 1378 quads - 0:00.00 +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/SoapDispenser_1/Geom/Cap/pCylinder223: regular subdivision done - 1 iterations: 250 faces => 980 quads - 0:00.00 +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 952 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube533: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 241MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder446: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/WallHinges/pSphere79: regular subdivision done - 1 iterations: 96 faces => 372 quads - 0:00.00 +00:00:03 242MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Doors/pCube633: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 241MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 460 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder489: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom1/pCylinder363: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder439: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 241MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 264 prims, 1 key +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2616 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/WallHinges/pSphere63: regular subdivision done - 1 iterations: 96 faces => 372 quads - 0:00.00 +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder449: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/West_grp/IronBoard_1/Geom/HandleIronBoard1/polySurface95: regular subdivision done - 1 iterations: 110 faces => 420 quads - 0:00.00 +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1080 prims, 1 key +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 372 prims, 1 key +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 780 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube558: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/SpiceBox_1/Geom/pCube636: regular subdivision done - 1 iterations: 214 faces => 856 quads - 0:00.00 +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/Spatula_1/Geom/pPlane320: regular subdivision done - 1 iterations: 158 faces => 632 quads - 0:00.00 +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/West_grp/IronBoard_1/Geom/HandleIronBoard1/polySurface79: regular subdivision done - 1 iterations: 110 faces => 420 quads - 0:00.00 +00:00:03 242MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Curtains1/CurtainHolderLeft/pCylinder254: regular subdivision done - 1 iterations: 54 faces => 198 quads - 0:00.00 +00:00:03 239MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 372 prims, 1 key +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 980 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube538: regular subdivision done - 1 iterations: 192 faces => 780 quads - 0:00.00 +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1378 prims, 1 key +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus292: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder525: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 372 prims, 1 key +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Screws/pCylinder370: regular subdivision done - 1 iterations: 40 faces => 144 quads - 0:00.00 +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder419: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 242MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Sink/Faucet/pCylinder29: regular subdivision done - 1 iterations: 140 faces => 520 quads - 0:00.00 +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 241MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 372 prims, 1 key +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Fire_Stove/pCylinder106: regular subdivision done - 1 iterations: 120 faces => 464 quads - 0:00.00 +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 420 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube480: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube585: regular subdivision done - 1 iterations: 147 faces => 598 quads - 0:00.00 +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/PlateBClean_5/Geom/Plate: regular subdivision done - 1 iterations: 204 faces => 792 quads - 0:00.00 +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder427: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 856 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/Mixer_1/Geom/Cable/pCube472: regular subdivision done - 1 iterations: 126 faces => 504 quads - 0:00.00 +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 632 prims, 1 key +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube118: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 792 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube532: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus313: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/Mixer_1/Geom/Body/pPipe23: regular subdivision done - 1 iterations: 260 faces => 1040 quads - 0:00.00 +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/CookingUtensils_grp/Whisk_1/Geom/pCylinder543: regular subdivision done - 1 iterations: 192 faces => 744 quads - 0:00.00 +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder411: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder525: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 242MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Curtains1/CurtainHolderLeft/pCylinder253: regular subdivision done - 1 iterations: 108 faces => 414 quads - 0:00.00 +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder437: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 520 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Doors/pCube5: regular subdivision done - 1 iterations: 6 faces => 24 quads - 0:00.00 +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 464 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder473: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/PotBDark_2/Geom/Pot: regular subdivision done - 1 iterations: 262 faces => 1024 quads - 0:00.00 +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 198 prims, 1 key +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Outlet/Large/pCube463: regular subdivision done - 1 iterations: 343 faces => 1378 quads - 0:00.00 +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 780 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/SpiceBox_1/Geom/pCube635: regular subdivision done - 1 iterations: 146 faces => 584 quads - 0:00.00 +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 504 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/StoolWooden_1/Geom/pCylinder193: regular subdivision done - 1 iterations: 160 faces => 600 quads - 0:00.00 +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus322: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 144 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder524: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus291: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/SoapSponge_1/Geom/SoapSponge: regular subdivision done - 1 iterations: 52 faces => 208 quads - 0:00.00 +00:00:03 243MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom1/pCylinder361: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 243MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1040 prims, 1 key +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 744 prims, 1 key +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 414 prims, 1 key +00:00:03 242MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder470: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 24 prims, 1 key +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder464: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 598 prims, 1 key +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Knobs/pSphere34: regular subdivision done - 1 iterations: 50 faces => 190 quads - 0:00.00 +00:00:03 244MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Sink/Faucet/pPipe12: regular subdivision done - 1 iterations: 300 faces => 1200 quads - 0:00.00 +00:00:03 242MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Sink/Faucet/pSphere57: regular subdivision done - 1 iterations: 520 faces => 2040 quads - 0:00.00 +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1024 prims, 1 key +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/PlateBClean_2/Geom/Plate: regular subdivision done - 1 iterations: 204 faces => 792 quads - 0:00.00 +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 584 prims, 1 key +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1378 prims, 1 key +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Screws/pCylinder372: regular subdivision done - 1 iterations: 40 faces => 144 quads - 0:00.00 +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube524: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 243MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube549: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 208 prims, 1 key +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder409: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube551: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom1/pCylinder357: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/Mixer_1/Geom/Body/pPipe21: regular subdivision done - 1 iterations: 260 faces => 1040 quads - 0:00.00 +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder474: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/West_grp/IronBoard_1/Geom/IroningBoard/pPlane327: regular subdivision done - 1 iterations: 46 faces => 184 quads - 0:00.00 +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder472: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 242MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 190 prims, 1 key +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube554: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1040 prims, 1 key +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1200 prims, 1 key +00:00:03 244MB | 5% done - 65 rays/pixel +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/SpiceBox_2/Geom/pCube635: regular subdivision done - 1 iterations: 146 faces => 584 quads - 0:00.00 +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder432: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/PotBLight_2/Geom/Pot: regular subdivision done - 1 iterations: 262 faces => 1024 quads - 0:00.00 +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 144 prims, 1 key +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2040 prims, 1 key +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1024 prims, 1 key +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/West_grp/TinCanA_1/Geom/TinCan: regular subdivision done - 1 iterations: 600 faces => 2376 quads - 0:00.00 +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder531: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus337: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 420 prims, 1 key +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube572: regular subdivision done - 1 iterations: 88 faces => 352 quads - 0:00.00 +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder533: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder440: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder438: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 184 prims, 1 key +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus312: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder441: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Knobs/pSphere42: regular subdivision done - 1 iterations: 50 faces => 190 quads - 0:00.00 +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 792 prims, 1 key +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder479: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube433: regular subdivision done - 1 iterations: 210 faces => 840 quads - 0:00.00 +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 584 prims, 1 key +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/West_grp/IronBoard_1/Geom/IroningBoard/pCylinder336: regular subdivision done - 1 iterations: 60 faces => 200 quads - 0:00.00 +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube526: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 245MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/PotBDark_1/Geom/Pot: regular subdivision done - 1 iterations: 262 faces => 1024 quads - 0:00.00 +00:00:03 245MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 245MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube548: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 245MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder474: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom1/pCylinder359: regular subdivision done - 1 iterations: 80 faces => 312 quads - 0:00.00 +00:00:03 245MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 352 prims, 1 key +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 245MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 245MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 245MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2376 prims, 1 key +00:00:03 244MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder532: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 245MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 245MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder420: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 245MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 190 prims, 1 key +00:00:03 245MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 245MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube428: regular subdivision done - 1 iterations: 210 faces => 840 quads - 0:00.00 +00:00:03 244MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder478: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 245MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/StoolWooden_1/Geom/pCylinder194: regular subdivision done - 1 iterations: 160 faces => 600 quads - 0:00.00 +00:00:03 245MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/PlateBClean_3/Geom/Plate: regular subdivision done - 1 iterations: 204 faces => 792 quads - 0:00.00 +00:00:03 245MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 840 prims, 1 key +00:00:03 245MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 245MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 200 prims, 1 key +00:00:03 245MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder426: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 245MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Sink/Faucet/pPipe18: regular subdivision done - 1 iterations: 300 faces => 1200 quads - 0:00.00 +00:00:03 245MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/CupShelf/Shelf/Rings/pCube406: regular subdivision done - 1 iterations: 136 faces => 544 quads - 0:00.00 +00:00:03 245MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus336: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 245MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube432: regular subdivision done - 1 iterations: 210 faces => 840 quads - 0:00.00 +00:00:03 246MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1024 prims, 1 key +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 245MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube556: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom1/pCylinder354: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 245MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/Mixer_1/Geom/Mixer/pCylinder258: regular subdivision done - 1 iterations: 84 faces => 312 quads - 0:00.00 +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder476: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube571: regular subdivision done - 1 iterations: 88 faces => 352 quads - 0:00.00 +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/CookingUtensils_grp/TinCanB_1/Geom/TinCan: regular subdivision done - 1 iterations: 156 faces => 600 quads - 0:00.00 +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus311: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus318: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 245MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder430: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/West_grp/TinCanA_2/Geom/TinCan: regular subdivision done - 1 iterations: 600 faces => 2376 quads - 0:00.00 +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 840 prims, 1 key +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 792 prims, 1 key +00:00:03 245MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 544 prims, 1 key +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/PlateBClean_1/Geom/Plate: regular subdivision done - 1 iterations: 204 faces => 792 quads - 0:00.00 +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder527: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus301: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder520: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/PotBLight_1/Geom/Pot: regular subdivision done - 1 iterations: 262 faces => 1024 quads - 0:00.00 +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom/pCylinder359: regular subdivision done - 1 iterations: 80 faces => 312 quads - 0:00.00 +00:00:03 247MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/TopCabinetHinges/pCylinder156: regular subdivision done - 1 iterations: 420 faces => 1640 quads - 0:00.00 +00:00:03 245MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder480: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 352 prims, 1 key +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom/pCylinder360: regular subdivision done - 1 iterations: 80 faces => 312 quads - 0:00.00 +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Fire_Stove/pCylinder120: regular subdivision done - 1 iterations: 120 faces => 464 quads - 0:00.00 +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 245MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube534: regular subdivision done - 1 iterations: 90 faces => 360 quads - 0:00.00 +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder452: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2376 prims, 1 key +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 840 prims, 1 key +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube521: regular subdivision done - 1 iterations: 192 faces => 780 quads - 0:00.00 +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 792 prims, 1 key +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/BottleShort_1/Geom/Bottle: regular subdivision done - 1 iterations: 204 faces => 792 quads - 0:00.00 +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/PlateBClean_4/Geom/Plate: regular subdivision done - 1 iterations: 204 faces => 792 quads - 0:00.00 +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder438: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/Spatula_1/Geom/pPlane319: regular subdivision done - 1 iterations: 48 faces => 192 quads - 0:00.00 +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus339: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus335: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 247MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/WallHinges/pSphere66: regular subdivision done - 1 iterations: 96 faces => 372 quads - 0:00.00 +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom/pCylinder353: regular subdivision done - 1 iterations: 104 faces => 400 quads - 0:00.00 +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1024 prims, 1 key +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube574: regular subdivision done - 1 iterations: 88 faces => 352 quads - 0:00.00 +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1640 prims, 1 key +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1200 prims, 1 key +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 464 prims, 1 key +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 360 prims, 1 key +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/Toaster_1/Geom/PlasticPieces/pCube590: regular subdivision done - 1 iterations: 328 faces => 1308 quads - 0:00.00 +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder440: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube427: regular subdivision done - 1 iterations: 210 faces => 840 quads - 0:00.00 +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder431: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 247MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube431: regular subdivision done - 1 iterations: 210 faces => 840 quads - 0:00.00 +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 780 prims, 1 key +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/Hook_7/Geom/Hook: regular subdivision done - 1 iterations: 240 faces => 936 quads - 0:00.00 +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube555: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 936 prims, 1 key +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 792 prims, 1 key +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 247MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube584: regular subdivision done - 1 iterations: 192 faces => 780 quads - 0:00.00 +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder524: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus316: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/AirVent/Fan/pCylinder557: regular subdivision done - 1 iterations: 72 faces => 272 quads - 0:00.00 +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube547: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 352 prims, 1 key +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder483: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder444: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 840 prims, 1 key +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder435: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 792 prims, 1 key +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus289: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 248MB | 10% done - 156 rays/pixel +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 840 prims, 1 key +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube539: regular subdivision done - 1 iterations: 192 faces => 780 quads - 0:00.00 +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder444: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder437: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 372 prims, 1 key +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 780 prims, 1 key +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/Hook_3/Geom/Hook: regular subdivision done - 1 iterations: 240 faces => 936 quads - 0:00.00 +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder529: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 780 prims, 1 key +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder523: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder480: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 272 prims, 1 key +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom1/pCylinder366: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1308 prims, 1 key +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder442: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube452: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus296: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder508: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 248MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Sink/Faucet/pPipe14: regular subdivision done - 1 iterations: 200 faces => 800 quads - 0:00.00 +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder515: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube434: regular subdivision done - 1 iterations: 210 faces => 840 quads - 0:00.00 +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus337: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 936 prims, 1 key +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Fire_Stove/pCylinder112: regular subdivision done - 1 iterations: 120 faces => 464 quads - 0:00.00 +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder424: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube550: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/Hook_5/Geom/Hook: regular subdivision done - 1 iterations: 240 faces => 936 quads - 0:00.00 +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 192 prims, 1 key +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder482: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder434: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 249MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube553: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 249MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 249MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 249MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder492: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 249MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 249MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 249MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/WallHinges/pSphere64: regular subdivision done - 1 iterations: 96 faces => 372 quads - 0:00.00 +00:00:03 249MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube573: regular subdivision done - 1 iterations: 88 faces => 352 quads - 0:00.00 +00:00:03 249MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 249MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder445: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/Iron_1/Geom/IronWire/pPipe31: regular subdivision done - 1 iterations: 130 faces => 520 quads - 0:00.00 +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 248MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 840 prims, 1 key +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder521: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 464 prims, 1 key +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder475: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom1/pCylinder365: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus338: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 936 prims, 1 key +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder479: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 249MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder461: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus288: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 248MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom/pCylinder362: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 372 prims, 1 key +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube430: regular subdivision done - 1 iterations: 210 faces => 840 quads - 0:00.00 +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 800 prims, 1 key +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 352 prims, 1 key +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder417: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder517: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 520 prims, 1 key +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus338: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder499: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 249MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder466: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 250MB | 15% done - 51 rays/pixel +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Clock_1/Geom/pCylinder214: regular subdivision done - 1 iterations: 248 faces => 972 quads - 0:00.00 +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/Hook_1/Geom/Hook: regular subdivision done - 1 iterations: 240 faces => 936 quads - 0:00.00 +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder484: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder433: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 250MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/WallHinges/Hook/pCylinder290: regular subdivision done - 1 iterations: 54 faces => 198 quads - 0:00.00 +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus298: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus315: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 840 prims, 1 key +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder493: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder410: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom1/pCylinder355: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 250MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Sink/Faucet/pPipe17: regular subdivision done - 1 iterations: 300 faces => 1200 quads - 0:00.00 +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 250MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/CupShelf/Shelf/Rings/pCube403: regular subdivision done - 1 iterations: 136 faces => 544 quads - 0:00.00 +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder528: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder476: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube531: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus339: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 972 prims, 1 key +00:00:03 251MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus305: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube535: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 251MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder510: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 251MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 251MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 198 prims, 1 key +00:00:03 251MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus310: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 251MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/BottleMediumNoCap_2/Geom/BottleMedium: regular subdivision done - 1 iterations: 120 faces => 456 quads - 0:00.00 +00:00:03 251MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 251MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 251MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/Hook_2/Geom/Hook: regular subdivision done - 1 iterations: 240 faces => 936 quads - 0:00.00 +00:00:03 251MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus301: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 251MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 251MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder504: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom1/pCylinder353: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 252MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1200 prims, 1 key +00:00:03 252MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 544 prims, 1 key +00:00:03 252MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 252MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Sink/Faucet/pSphere13: regular subdivision done - 1 iterations: 520 faces => 2040 quads - 0:00.00 +00:00:03 252MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube570: regular subdivision done - 1 iterations: 88 faces => 352 quads - 0:00.00 +00:00:03 252MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder427: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube528: regular subdivision done - 1 iterations: 147 faces => 598 quads - 0:00.00 +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus293: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 251MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 936 prims, 1 key +00:00:03 252MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/pPlane355: regular subdivision done - 1 iterations: 25 faces => 100 quads - 0:00.00 +00:00:03 252MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 252MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Clock_1/Geom/polySurface66: regular subdivision done - 1 iterations: 132 faces => 504 quads - 0:00.00 +00:00:03 252MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 252MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 456 prims, 1 key +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Handles/pCylinder134: regular subdivision done - 1 iterations: 72 faces => 272 quads - 0:00.00 +00:00:03 250MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder495: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 252MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/Mixer_1/Geom/Body/pCube478: regular subdivision done - 1 iterations: 56 faces => 224 quads - 0:00.00 +00:00:03 252MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 936 prims, 1 key +00:00:03 252MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder530: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group7/pCube399: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom1/pCylinder362: regular subdivision done - 1 iterations: 96 faces => 368 quads - 0:00.00 +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/pPipe34: regular subdivision done - 1 iterations: 140 faces => 560 quads - 0:00.00 +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 368 prims, 1 key +00:00:03 252MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder500: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 252MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 352 prims, 1 key +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder460: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 252MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 2040 prims, 1 key +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube544: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 252MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 252MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 598 prims, 1 key +00:00:03 250MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube560: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 252MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 100 prims, 1 key +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus314: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus328: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube552: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus309: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/Hook_4/Geom/Hook: regular subdivision done - 1 iterations: 240 faces => 936 quads - 0:00.00 +00:00:03 252MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 252MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 252MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 272 prims, 1 key +00:00:03 251MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 252MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 224 prims, 1 key +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1/Geom/Decorations/pPlane364: regular subdivision done - 1 iterations: 25 faces => 100 quads - 0:00.00 +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder498: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder509: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 560 prims, 1 key +00:00:03 252MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus307: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 253MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/CupShelf/Shelf/Rings/pCube407: regular subdivision done - 1 iterations: 136 faces => 544 quads - 0:00.00 +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder425: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallFruits_set/WallFlower_grp/WallFlower_1/Geom/pPlane137: regular subdivision done - 1 iterations: 66 faces => 264 quads - 0:00.00 +00:00:03 252MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 504 prims, 1 key +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 253MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Windows_Frame/WindowStill/Window_Frame_Arch/pCylinder217: regular subdivision done - 1 iterations: 120 faces => 460 quads - 0:00.00 +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/Iron_1/Geom/pCylinder349: regular subdivision done - 1 iterations: 120 faces => 460 quads - 0:00.00 +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus321: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder460: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 936 prims, 1 key +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 100 prims, 1 key +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder515: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/BroomParts/pPipe32: regular subdivision done - 1 iterations: 80 faces => 320 quads - 0:00.00 +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder528: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube540: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube439: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 544 prims, 1 key +00:00:03 252MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/BottleMediumNoCap_3/Geom/BottleMedium: regular subdivision done - 1 iterations: 120 faces => 456 quads - 0:00.00 +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 264 prims, 1 key +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus322: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder521: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder503: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Broom_1/Geom/Broom1/pCylinder360: regular subdivision done - 1 iterations: 80 faces => 312 quads - 0:00.00 +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder411: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus308: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 460 prims, 1 key +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/Hook_6/Geom/Hook: regular subdivision done - 1 iterations: 240 faces => 936 quads - 0:00.00 +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus325: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 936 prims, 1 key +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder501: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 320 prims, 1 key +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Clock_1/Geom/polySurface67: regular subdivision done - 1 iterations: 110 faces => 440 quads - 0:00.00 +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus334: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 460 prims, 1 key +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube537: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube438: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 312 prims, 1 key +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Handles/pCylinder132: regular subdivision done - 1 iterations: 72 faces => 272 quads - 0:00.00 +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder508: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus320: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 456 prims, 1 key +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder529: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 253MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/CupShelf/Shelf/Rings/pCube405: regular subdivision done - 1 iterations: 136 faces => 544 quads - 0:00.00 +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder523: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 253MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Sink/Faucet/pPipe13: regular subdivision done - 1 iterations: 200 faces => 800 quads - 0:00.00 +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus321: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus306: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder522: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube536: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 272 prims, 1 key +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 253MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/WallHinges/pSphere70: regular subdivision done - 1 iterations: 96 faces => 372 quads - 0:00.00 +00:00:03 254MB | 20% done - 142 rays/pixel +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 440 prims, 1 key +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus326: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/BottleMediumNoCap_1/Geom/BottleMedium: regular subdivision done - 1 iterations: 120 faces => 456 quads - 0:00.00 +00:00:03 254MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 254MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 254MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 544 prims, 1 key +00:00:03 254MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder451: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 254MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 254MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder526: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 254MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder426: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 254MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder486: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 254MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 800 prims, 1 key +00:00:03 254MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 254MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 254MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Sink/Faucet/pCylinder70: regular subdivision done - 1 iterations: 50 faces => 180 quads - 0:00.00 +00:00:03 254MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 254MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder522: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 254MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/TopCabinetHinges/pPlane17: regular subdivision done - 1 iterations: 238 faces => 952 quads - 0:00.00 +00:00:03 254MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 372 prims, 1 key +00:00:03 254MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Clock_1/Geom/polySurface90: regular subdivision done - 1 iterations: 110 faces => 440 quads - 0:00.00 +00:00:03 254MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 254MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 456 prims, 1 key +00:00:03 254MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder518: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Knobs/pSphere43: regular subdivision done - 1 iterations: 50 faces => 190 quads - 0:00.00 +00:00:03 254MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 254MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder487: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/BottleMediumNoCap_6/Geom/BottleMedium: regular subdivision done - 1 iterations: 120 faces => 456 quads - 0:00.00 +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder494: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 254MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Screws/pCylinder397: regular subdivision done - 1 iterations: 120 faces => 460 quads - 0:00.00 +00:00:03 253MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube586: regular subdivision done - 1 iterations: 147 faces => 598 quads - 0:00.00 +00:00:03 255MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Curtains1/CurtainHolderRight/pTorus160: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 180 prims, 1 key +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder481: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus303: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube116: regular subdivision done - 1 iterations: 6 faces => 24 quads - 0:00.00 +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 440 prims, 1 key +00:00:03 254MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder502: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 254MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder505: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 190 prims, 1 key +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder465: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/TeaKettle_1/Geom/pSphere47: regular subdivision done - 1 iterations: 252 faces => 984 quads - 0:00.00 +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder507: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube530: regular subdivision done - 1 iterations: 147 faces => 598 quads - 0:00.00 +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder493: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 598 prims, 1 key +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus317: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder459: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 255MB | 25% done - 87 rays/pixel +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 952 prims, 1 key +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 24 prims, 1 key +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube442: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube575: regular subdivision done - 1 iterations: 88 faces => 352 quads - 0:00.00 +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 456 prims, 1 key +00:00:03 255MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Curtains1/CurtainHolderRight/pTorus161: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 460 prims, 1 key +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 253MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/Toaster_1/Geom/Cable/pPipe28: regular subdivision done - 1 iterations: 130 faces => 520 quads - 0:00.00 +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 984 prims, 1 key +00:00:03 255MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Sink/Faucet/pCylinder262: regular subdivision done - 1 iterations: 70 faces => 260 quads - 0:00.00 +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 260 prims, 1 key +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus304: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder409: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 255MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Curtains1/CurtainHolderRight/pCylinder253: regular subdivision done - 1 iterations: 108 faces => 414 quads - 0:00.00 +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/BottleMediumNoCap_4/Geom/BottleMedium: regular subdivision done - 1 iterations: 120 faces => 456 quads - 0:00.00 +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Fire_Stove/pCylinder118: regular subdivision done - 1 iterations: 72 faces => 272 quads - 0:00.00 +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder514: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 520 prims, 1 key +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Clock_1/Geom/pCube457: regular subdivision done - 1 iterations: 142 faces => 568 quads - 0:00.00 +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder458: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 598 prims, 1 key +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus306: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder488: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 568 prims, 1 key +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube115: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 414 prims, 1 key +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Screws/pCylinder346: regular subdivision done - 1 iterations: 120 faces => 460 quads - 0:00.00 +00:00:03 256MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 272 prims, 1 key +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/StoolWooden_1/Geom/pCylinder195: regular subdivision done - 1 iterations: 160 faces => 600 quads - 0:00.00 +00:00:03 256MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube119: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 255MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 255MB | 30% done - 303 rays/pixel +00:00:03 256MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 256MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 256MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 456 prims, 1 key +00:00:03 256MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube525: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 256MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus295: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 256MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 352 prims, 1 key +00:00:03 255MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/Toaster_1/Geom/Cable/pPlane151: regular subdivision done - 1 iterations: 1 faces => 4 quads - 0:00.00 +00:00:03 256MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 460 prims, 1 key +00:00:03 256MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube443: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 256MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Curtains1/CurtainHolderRight/pSphere83: regular subdivision done - 1 iterations: 110 faces => 420 quads - 0:00.00 +00:00:03 256MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 256MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Fire_Stove/pCylinder108: regular subdivision done - 1 iterations: 72 faces => 272 quads - 0:00.00 +00:00:03 256MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 420 prims, 1 key +00:00:03 256MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 256MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 256MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Curtains1/CurtainHolderLeft/pCylinder287: regular subdivision done - 1 iterations: 96 faces => 360 quads - 0:00.00 +00:00:03 256MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 4 prims, 1 key +00:00:03 256MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 256MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube523: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 256MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus300: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 256MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 256MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/BottleMediumNoCap_5/Geom/BottleMedium: regular subdivision done - 1 iterations: 120 faces => 456 quads - 0:00.00 +00:00:03 256MB | 35% done - 188 rays/pixel +00:00:03 256MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube576: regular subdivision done - 1 iterations: 86 faces => 350 quads - 0:00.00 +00:00:03 256MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder416: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 256MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/TopCabinetHinges/pPlane15: regular subdivision done - 1 iterations: 238 faces => 952 quads - 0:00.00 +00:00:03 256MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 272 prims, 1 key +00:00:03 256MB | [subdiv] /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/FoldingTable_1/Geom/group7/pCube393: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 256MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus289: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 257MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/Toaster_1/Geom/Cable/pCube616: regular subdivision done - 1 iterations: 126 faces => 504 quads - 0:00.00 +00:00:03 256MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus320: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 256MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube117: regular subdivision done - 1 iterations: 170 faces => 680 quads - 0:00.00 +00:00:03 256MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/FlowerPotA_4/Geom/FlowerPot: regular subdivision done - 1 iterations: 140 faces => 540 quads - 0:00.00 +00:00:03 256MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 256MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 256MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 456 prims, 1 key +00:00:03 256MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Handles/pCylinder130: regular subdivision done - 1 iterations: 112 faces => 432 quads - 0:00.00 +00:00:03 256MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 350 prims, 1 key +00:00:03 257MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 256MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Curtains1/CurtainHolderRight/pCylinder287: regular subdivision done - 1 iterations: 96 faces => 360 quads - 0:00.00 +00:00:03 257MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 432 prims, 1 key +00:00:03 257MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder418: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 257MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 257MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 952 prims, 1 key +00:00:03 257MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 257MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 257MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus288: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 256MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 257MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 257MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 680 prims, 1 key +00:00:03 257MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 540 prims, 1 key +00:00:03 256MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 360 prims, 1 key +00:00:03 257MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/TableTop_grp/FlowerPotA_5/Geom/FlowerPot: regular subdivision done - 1 iterations: 140 faces => 540 quads - 0:00.00 +00:00:03 257MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Knobs/pSphere40: regular subdivision done - 1 iterations: 50 faces => 190 quads - 0:00.00 +00:00:03 257MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 504 prims, 1 key +00:00:03 257MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 360 prims, 1 key +00:00:03 257MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube527: regular subdivision done - 1 iterations: 144 faces => 576 quads - 0:00.00 +00:00:03 257MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder511: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 257MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 257MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Knobs/pSphere36: regular subdivision done - 1 iterations: 419 faces => 1662 quads - 0:00.00 +00:00:03 257MB | 40% done - 59 rays/pixel +00:00:03 257MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder467: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 257MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus296: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 258MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 257MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube445: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 257MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 540 prims, 1 key +00:00:03 257MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/CookingUtensils_grp/WoodenSpoonB_1/Geom/WoodenSpoon: regular subdivision done - 1 iterations: 200 faces => 780 quads - 0:00.00 +00:00:03 257MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 576 prims, 1 key +00:00:03 257MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/TopCabinetHinges/pCylinder369: regular subdivision done - 1 iterations: 420 faces => 1640 quads - 0:00.00 +00:00:03 257MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus287: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 258MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/Doors/pCube249: regular subdivision done - 1 iterations: 192 faces => 768 quads - 0:00.00 +00:00:03 258MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Handles/pCylinder102: regular subdivision done - 1 iterations: 112 faces => 432 quads - 0:00.00 +00:00:03 258MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 257MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/Base/pCube132: regular subdivision done - 1 iterations: 204 faces => 816 quads - 0:00.00 +00:00:03 258MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1662 prims, 1 key +00:00:03 257MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 190 prims, 1 key +00:00:03 258MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 258MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/FlowerPotA_3/Geom/FlowerPot: regular subdivision done - 1 iterations: 140 faces => 540 quads - 0:00.00 +00:00:03 258MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder509: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 259MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus317: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 259MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 780 prims, 1 key +00:00:03 259MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 259MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus316: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 259MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 432 prims, 1 key +00:00:03 259MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder432: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 259MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 768 prims, 1 key +00:00:03 259MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1640 prims, 1 key +00:00:03 259MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 816 prims, 1 key +00:00:03 259MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/WallPineapple_1/Geom/Body/pCube587: regular subdivision done - 1 iterations: 86 faces => 350 quads - 0:00.00 +00:00:03 259MB | [subdiv] /Kitchen_set/Props_grp/West_grp/IronBoard_1/Geom/IroningBoard/pCylinder338: regular subdivision done - 1 iterations: 120 faces => 460 quads - 0:00.00 +00:00:03 259MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 540 prims, 1 key +00:00:03 259MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Sink/Faucet/pPipe19: regular subdivision done - 1 iterations: 220 faces => 880 quads - 0:00.00 +00:00:03 259MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 259MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 258MB | 45% done - 99 rays/pixel +00:00:03 259MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 257MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 259MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 350 prims, 1 key +00:00:03 259MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 259MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder430: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 259MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus294: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 259MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 460 prims, 1 key +00:00:03 259MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube437: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 259MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus315: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 259MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 880 prims, 1 key +00:00:03 259MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder501: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 259MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/TopCabinetHinges/pCylinder81: regular subdivision done - 1 iterations: 420 faces => 1640 quads - 0:00.00 +00:00:03 259MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/FlowerPotA_6/Geom/FlowerPot: regular subdivision done - 1 iterations: 140 faces => 540 quads - 0:00.00 +00:00:03 259MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus318: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 259MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Fire_Stove/pCylinder111: regular subdivision done - 1 iterations: 72 faces => 272 quads - 0:00.00 +00:00:03 259MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 259MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 259MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 540 prims, 1 key +00:00:03 259MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 259MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 259MB | 50% done - 81 rays/pixel +00:00:03 259MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 259MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus293: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 259MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 272 prims, 1 key +00:00:03 259MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder431: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 259MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube440: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 259MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1640 prims, 1 key +00:00:03 259MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 259MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus297: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 259MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder439: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 259MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube436: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 259MB | 55% done - 75 rays/pixel +00:00:03 259MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/FlowerPotA_2/Geom/FlowerPot: regular subdivision done - 1 iterations: 140 faces => 540 quads - 0:00.00 +00:00:03 259MB | [subdiv] /Kitchen_set/Props_grp/West_grp/IronBoard_1/Geom/IroningBoard/pCylinder339: regular subdivision done - 1 iterations: 120 faces => 460 quads - 0:00.00 +00:00:03 259MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/Toaster_1/Geom/PlasticPieces/pCube595: regular subdivision done - 1 iterations: 54 faces => 216 quads - 0:00.00 +00:00:03 259MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 259MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/Mixer_1/Geom/Body/pCube477: regular subdivision done - 1 iterations: 56 faces => 224 quads - 0:00.00 +00:00:03 259MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus307: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 259MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus290: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 259MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube435: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 259MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus319: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 261MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 261MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 261MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus294: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 259MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 261MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 540 prims, 1 key +00:00:03 261MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 460 prims, 1 key +00:00:03 259MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 261MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 216 prims, 1 key +00:00:03 260MB | 60% done - 169 rays/pixel +00:00:03 261MB | [subdiv] /Kitchen_set/Props_grp/West_grp/IronBoard_1/Geom/IroningBoard/pCylinder340: regular subdivision done - 1 iterations: 120 faces => 460 quads - 0:00.00 +00:00:03 261MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 261MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 261MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 261MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 261MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus313: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 261MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 224 prims, 1 key +00:00:03 261MB | [subdiv] /Kitchen_set/Props_grp/West_grp/IronBoard_1/Geom/IroningBoard/pCylinder341: regular subdivision done - 1 iterations: 120 faces => 460 quads - 0:00.00 +00:00:03 261MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/FlowerPotA_1/Geom/FlowerPot: regular subdivision done - 1 iterations: 140 faces => 540 quads - 0:00.00 +00:00:03 261MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus300: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 261MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/Mixer_1/Geom/Handle/pPipe24: regular subdivision done - 1 iterations: 180 faces => 720 quads - 0:00.00 +00:00:03 261MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/Mixer_1/Geom/Cable/pCylinder301: regular subdivision done - 1 iterations: 120 faces => 460 quads - 0:00.00 +00:00:03 261MB | 65% done - 2218 rays/pixel +00:00:03 261MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 261MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 460 prims, 1 key +00:00:03 261MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Knobs/pSphere35: regular subdivision done - 1 iterations: 50 faces => 190 quads - 0:00.00 +00:00:03 261MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus308: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 261MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/CerealBoxA_2/Geom/CerealBox: regular subdivision done - 1 iterations: 1373 faces => 5492 quads - 0:00.01 +00:00:03 261MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 261MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 261MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 261MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 460 prims, 1 key +00:00:03 261MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Sink/Faucet/polySurface77: regular subdivision done - 1 iterations: 48 faces => 192 quads - 0:00.00 +00:00:03 261MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 192 prims, 1 key +00:00:03 261MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube444: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 261MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 261MB | 70% done - 294 rays/pixel +00:00:03 262MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Curtains1/CurtainHolderRight/pCylinder254: regular subdivision done - 1 iterations: 54 faces => 198 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 198 prims, 1 key +00:00:03 261MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 720 prims, 1 key +00:00:03 261MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/WallHinges/pSphere59: regular subdivision done - 1 iterations: 96 faces => 372 quads - 0:00.00 +00:00:03 261MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 261MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/DryingRack_grp/WoodenDryingRack_1/Geom/WoodenPieces/pCube441: regular subdivision done - 1 iterations: 150 faces => 600 quads - 0:00.00 +00:00:03 261MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus304: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 261MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 540 prims, 1 key +00:00:03 261MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus292: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 261MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 460 prims, 1 key +00:00:03 261MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/CookingUtensils_grp/SpoonSpaghetti_1/Geom/SpoonSpaghetti: regular subdivision done - 1 iterations: 354 faces => 1416 quads - 0:00.00 +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus331: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 261MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus327: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 261MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 190 prims, 1 key +00:00:03 261MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/TableTop_grp/Spoon_2/Geom/Spoon: regular subdivision done - 1 iterations: 136 faces => 544 quads - 0:00.00 +00:00:03 261MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Handles/pCylinder131: regular subdivision done - 1 iterations: 72 faces => 272 quads - 0:00.00 +00:00:03 261MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder514: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 261MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 600 prims, 1 key +00:00:03 261MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 5492 prims, 1 key +00:00:03 261MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 372 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/Spoon_1/Geom/Spoon: regular subdivision done - 1 iterations: 136 faces => 544 quads - 0:00.00 +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Countertop_grp/Mixer_1/Geom/Handle/pPipe22: regular subdivision done - 1 iterations: 180 faces => 720 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 262MB | 75% done - 576 rays/pixel +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 272 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 544 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1416 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Knobs/pSphere44: regular subdivision done - 1 iterations: 50 faces => 190 quads - 0:00.00 +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Knobs/pSphere38: regular subdivision done - 1 iterations: 50 faces => 190 quads - 0:00.00 +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder473: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 261MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/CerealBoxA_3/Geom/CerealBox: regular subdivision done - 1 iterations: 1373 faces => 5492 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 720 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 262MB | 80% done - 1636 rays/pixel +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Knobs/pSphere37: regular subdivision done - 1 iterations: 50 faces => 190 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 190 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus297: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 544 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus324: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 262MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/WallHinges/pSphere58: regular subdivision done - 1 iterations: 96 faces => 372 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Sink/Faucet/polySurface75: regular subdivision done - 1 iterations: 48 faces => 192 quads - 0:00.00 +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Fire_Stove/pCylinder110: regular subdivision done - 1 iterations: 56 faces => 208 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 190 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus333: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/Spoon_4/Geom/Spoon: regular subdivision done - 1 iterations: 136 faces => 544 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 5492 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 190 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 192 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 208 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Sink/Faucet/pSphere85: regular subdivision done - 1 iterations: 96 faces => 372 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 544 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/AirVent/pCylinder168: regular subdivision done - 1 iterations: 120 faces => 460 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 372 prims, 1 key +00:00:03 262MB | 85% done - 39501 rays/pixel +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/Spoon_3/Geom/Spoon: regular subdivision done - 1 iterations: 136 faces => 544 quads - 0:00.00 +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus298: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Fire_Stove/pCylinder109: regular subdivision done - 1 iterations: 120 faces => 464 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 544 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 372 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 460 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Fire_Stove/pCylinder119: regular subdivision done - 1 iterations: 56 faces => 208 quads - 0:00.00 +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder500: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder513: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus330: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 464 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/PanA_1/Geom/pCylinder379: regular subdivision done - 1 iterations: 120 faces => 460 quads - 0:00.00 +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder519: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus299: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/Spoon_5/Geom/Spoon: regular subdivision done - 1 iterations: 136 faces => 544 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 208 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 460 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Cupboard_grp/CerealBoxA_1/Geom/CerealBox: regular subdivision done - 1 iterations: 1373 faces => 5492 quads - 0:00.01 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 544 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder502: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder452: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus332: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus305: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder423: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 262MB | [subdiv] /Kitchen_set/Arch_grp/Kitchen_1/Geom/Cabinets/TopCabinetHinges/pCylinder154: regular subdivision done - 1 iterations: 420 faces => 1640 quads - 0:00.00 +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/StoveArea_grp/Stove_1/Geom/Knobs/pSphere39: regular subdivision done - 1 iterations: 50 faces => 190 quads - 0:00.00 +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus314: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 190 prims, 1 key +00:00:03 262MB | 90% done - 713 rays/pixel +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1640 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 5492 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus290: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/CupCBlue_2/Geom/Cup: regular subdivision done - 1 iterations: 316 faces => 1240 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1240 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/NorthWall_grp/CupCBlue_1/Geom/Cup: regular subdivision done - 1 iterations: 316 faces => 1240 quads - 0:00.00 +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder516: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 262MB | 95% done - 0 rays/pixel +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pCylinder472: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1240 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus333: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus302: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus336: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus335: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus303: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/DiningTable_grp/TableTop_grp/CupCRed_1/Geom/Cup: regular subdivision done - 1 iterations: 316 faces => 1240 quads - 0:00.00 +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus329: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1240 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels1/pTorus310: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus295: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus334: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/Sink_grp/SoapDish_1/Geom/SoapDish: regular subdivision done - 1 iterations: 138 faces => 552 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 552 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder516: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus331: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus330: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pCylinder507: regular subdivision done - 1 iterations: 60 faces => 220 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 220 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/SinkFloor_grp/Rug_1/Geom/Tassels/pTorus329: regular subdivision done - 1 iterations: 100 faces => 400 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 400 prims, 1 key +00:00:03 262MB | [subdiv] /Kitchen_set/Props_grp/North_grp/SinkArea_grp/CookingUtensils_grp/WoodenSpoonA_1/Geom/WoodenSpoon: regular subdivision done - 1 iterations: 220 faces => 860 quads - 0:00.00 +00:00:03 262MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 860 prims, 1 key +00:00:03 262MB | 100% done - 0 rays/pixel +00:00:03 262MB | render done in 0:01.063 +00:00:03 262MB | [driver_tiff] writing file `testrender.tif' +00:00:03 262MB | render done +00:00:03 262MB | +00:00:03 262MB | ----------------------------------------------------------------------------------- +00:00:03 262MB | scene creation time 0:00.34 machine utilization (0.11%) +00:00:03 262MB | plugin loading 0:00.08 +00:00:03 262MB | unaccounted 0:00.25 +00:00:03 262MB | ----------------------------------------------------------------------------------- +00:00:03 262MB | frame time 0:03.86 machine utilization (15.17%) +00:00:03 262MB | node init 0:00.39 +00:00:03 262MB | driver init/close 0:00.01 +00:00:03 262MB | rendering 0:01.06 +00:00:03 262MB | subdivision 0:00.03 +00:00:03 262MB | accel. building 0:00.37 +00:00:03 262MB | pixel rendering 0:00.64 +00:00:03 262MB | unaccounted 0:02.40 +00:00:03 262MB | ----------------------------------------------------------------------------------- +00:00:03 262MB | top session self-times by category +00:00:03 262MB | worker waiting 0:02.50 (65.58%) +00:00:03 262MB | subdivision 0:00.38 (10.15%) +00:00:03 262MB | InitializeNodes 0:00.37 ( 9.81%) +00:00:03 262MB | BVH::build 0:00.36 ( 9.61%) +00:00:03 262MB | thread blocked 0:00.05 ( 1.45%) +00:00:03 262MB | polymesh::intersect 0:00.02 ( 0.70%) +00:00:03 262MB | ----------------------------------------------------------------------------------- +00:00:03 262MB | top session self-times by node +00:00:04 262MB | worker waiting 0:02.50 (65.58%) +00:00:04 262MB | InitializeNodes 0:00.37 ( 9.81%) +00:00:04 262MB | standard_surface:surfShader 0:00.04 ( 1.06%) +00:00:04 262MB | surface closure 0:00.02 ( 0.56%) +00:00:04 262MB | usd:aiUsdShape2 0:00.02 ( 0.70%) +00:00:04 262MB | initializeAllNodes 0:00.00 ( 0.25%) +00:00:04 262MB | TraceCameraRay 0:00.00 ( 0.23%) +00:00:04 262MB | ----------------------------------------------------------------------------------- +00:00:04 262MB | peak CPU memory used 262.90MB +00:00:04 262MB | at startup 36.85MB +00:00:04 262MB | plugins 6.23MB +00:00:04 262MB | AOV samples 6.52MB +00:00:04 262MB | output buffers 0.23MB +00:00:04 262MB | framebuffers 0.31MB +00:00:04 262MB | node overhead 0.91MB +00:00:04 262MB | message passing 0.08MB +00:00:04 262MB | memory pools 30.05MB +00:00:04 262MB | geometry 78.05MB +00:00:04 262MB | subdivs 78.04MB +00:00:04 262MB | accel. structs 34.89MB +00:00:04 262MB | strings 12.00MB +00:00:04 262MB | profiler 0.49MB +00:00:04 262MB | unaccounted 56.27MB +00:00:04 262MB | ----------------------------------------------------------------------------------- +00:00:04 262MB | ray counts ( /pixel, /sample) (% total) (avg. hits) (max hits) +00:00:04 262MB | camera 192800 ( 10.04, 1.00) ( 12.10%) ( 0.91) ( 2) +00:00:04 262MB | shadow 1400650 ( 72.95, 7.26) ( 87.90%) ( 0.73) ( 1) +00:00:04 262MB | total 1593450 ( 82.99, 8.26) (100.00%) ( 0.75) ( 2) +00:00:04 262MB | by ray depth: 0 +00:00:04 262MB | total 100.0% +00:00:04 262MB | ----------------------------------------------------------------------------------- +00:00:04 262MB | shader calls ( /pixel, /sample) (% total) +00:00:04 262MB | primary 351368 ( 18.30, 1.82) (100.00%) +00:00:04 262MB | total 351368 ( 18.30, 1.82) (100.00%) +00:00:04 262MB | by ray depth: 0 +00:00:04 262MB | total 100.0% +00:00:04 262MB | ----------------------------------------------------------------------------------- +00:00:04 262MB | geometry (% hit ) (instances) ( init mem, final mem) +00:00:04 262MB | lists 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:04 262MB | procs 1 (100.0%) ( 0) ( 0.01, 0.01) +00:00:04 262MB | subdivs 1788 ( 83.0%) ( 0) ( 22.30, 78.04) +00:00:04 262MB | ----------------------------------------------------------------------------------- +00:00:04 262MB | geometric elements ( min) ( avg.) ( max) +00:00:04 262MB | objects (procs) 1788 ( 1788) ( 1788.0) ( 1788) +00:00:04 262MB | subdiv patches 275656 ( 1) ( 154.2) ( 14256) +00:00:04 262MB | ----------------------------------------------------------------------------------- +00:00:04 262MB | triangle tessellation ( min) ( avg.) ( max) (/ element) (% total) +00:00:04 262MB | subdivs 1914806 ( 8) ( 1290.3) ( 114048) ( 7.89) (100.00%) +00:00:04 262MB | iterations 1 1914806 ( 8) ( 1290.3) ( 114048) ( 7.89) (100.00%) +00:00:04 262MB | unique triangles 1914806 +00:00:04 262MB | CPU memory use 75.15MB +00:00:04 262MB | vertices 11.03MB +00:00:04 262MB | vertex indices 5.00MB +00:00:04 262MB | packed normals 3.68MB +00:00:04 262MB | normal indices 0.03MB +00:00:04 262MB | uniform indices 1.06MB +00:00:04 262MB | userdata 53.96MB +00:00:04 262MB | largest polymeshes by triangle count +00:00:04 262MB | 114048 tris -- /Kitchen_set/Props_grp/West_grp/StoolMetalWire_1/Geom/polySurface63 +00:00:04 262MB | 33584 tris -- /Kitchen_set/Props_grp/West_grp/PaperBagCrumpled_1/Geom/GroceryBag +00:00:04 262MB | 24080 tris -- /Kitchen_set/Props_grp/North_grp/NorthWall_grp/GarlicRope_1/Geom/pCylinder241 +00:00:04 262MB | 22240 tris -- /Kitchen_set/Props_grp/North_grp/NorthWall_grp/GarlicRope_1/Geom/pCylinder240 +00:00:04 262MB | 14552 tris -- /Kitchen_set/Props_grp/West_grp/FoldingTable_grp/BreadBag_1/Geom/Bread +00:00:04 262MB | ----------------------------------------------------------------------------------- +00:00:04 262MB | acceleration structures: (% total) +00:00:04 262MB | list 1 ( 0.07%) +00:00:04 262MB | bvh 1485 ( 99.93%) +00:00:04 262MB | total 1486 (100.00%) +00:00:04 262MB | ----------------------------------------------------------------------------------- +00:00:04 262MB | performance warnings: +00:00:04 262MB WARNING | Rendering CPU utilization was only 15%. Your render may be bound by a single threaded process or I/O. +00:00:04 262MB | ----------------------------------------------------------------------------------- +00:00:04 262MB | +00:00:04 262MB | releasing resources +00:00:04 119MB | unloading 1 plugin +00:00:04 119MB | closing usd_proc.dll ... +00:00:04 109MB | unloading plugins done +00:00:04 109MB | Arnold shutdown diff --git a/testsuite/test_0016/ref/reference.tif b/testsuite/test_0016/ref/reference.tif new file mode 100755 index 0000000000..b41198f861 Binary files /dev/null and b/testsuite/test_0016/ref/reference.tif differ diff --git a/testsuite/test_0017/README b/testsuite/test_0017/README new file mode 100755 index 0000000000..d27dcfb2e2 --- /dev/null +++ b/testsuite/test_0017/README @@ -0,0 +1,8 @@ +Testing override layers on the procedural. + +Testing override layers on the procedural by overriding the selection from the sphere to the torus. + +See trac#**** + +author: Pal Mezei + diff --git a/testsuite/test_0017/data/test.ass b/testsuite/test_0017/data/test.ass new file mode 100755 index 0000000000..c741420457 --- /dev/null +++ b/testsuite/test_0017/data/test.ass @@ -0,0 +1,108 @@ +### exported: Mon Dec 17 21:54:24 2018 +### from: Arnold 5.2.2.0 [30b8ba14] windows icc-17.0.2 oiio-2.0.1 osl-1.10.1 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 2018/12/04 22:02:04 +### host app: MtoA 3.1.3.wip 7d48f6c4 (develop) Maya 2018 +### bounds: -1 -8.268288 -1 1 -6.268287 1 +### user: blaines +### render_layer: defaultRenderLayer +### scene: D:/arnold/scenes/usd.ma + + + +options +{ + AA_samples 1 + outputs "RGBA RGBA myfilter mydriver" + xres 160 + yres 120 + pixel_aspect_ratio 1.33333325 + camera "perspShape" + frame 1 +} + +gaussian_filter +{ + name myfilter +} + +driver_tiff +{ + name mydriver + filename "testrender.tif" + color_space "sRGB" +} + +persp_camera +{ + name perspShape + matrix + 0.716910601 2.77555756e-17 -0.697165132 0 + -0.320169091 0.888310015 -0.329237103 0 + 0.619298756 0.459244281 0.636838853 0 + 2.41154099 -5.45881033 2.70130825 1 + near_clip 0.100000001 + far_clip 10000 + screen_window_min -1 -1 + screen_window_max 1 1 + shutter_start 0 + shutter_end 0 + shutter_type "box" + rolling_shutter "off" + rolling_shutter_duration 0 + motion_start 0 + motion_end 0 + exposure 0 + fov 54.4322243 + uv_remap 0 0 0 1 + declare maya_full_name constant STRING + maya_full_name "|persp|perspShape" +} + +distant_light +{ + name directionalLightShape1 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 0 0 1 + exposure 0 + cast_shadows on + cast_volumetric_shadows on + shadow_density 1 + samples 1 + normalize on + diffuse 1 + specular 1 + sss 1 + indirect 1 + max_bounces 999 + volume_samples 2 + volume 1 + aov "default" + angle 0 + declare maya_full_name constant STRING + maya_full_name "|directionalLight1|directionalLightShape1" +} + +usd +{ + name aiUsdShape2 + visibility 255 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 -7.26828718 0 1 + use_light_group off + override_nodes off + filename "variants.usd" + overrides 2 1 STRING +"#usda 1.0" +"#usda 1.0 +over \"ExampleModelingVariants\" ( + variants = { + string modelingVariant = \"Torus\" + } +) { }" +} + diff --git a/testsuite/test_0017/data/testrender.tif b/testsuite/test_0017/data/testrender.tif new file mode 100755 index 0000000000..f37b5fd7a1 Binary files /dev/null and b/testsuite/test_0017/data/testrender.tif differ diff --git a/testsuite/test_0017/data/variants.usd b/testsuite/test_0017/data/variants.usd new file mode 100755 index 0000000000..30c9491ffe --- /dev/null +++ b/testsuite/test_0017/data/variants.usd @@ -0,0 +1,332 @@ +#usda 1.0 +( + endTimeCode = 0 + startTimeCode = 0 + upAxis = "Z" +) + +def Xform "ExampleModelingVariants" ( + kind = "component" + variants = { + string modelingVariant = "Sphere" + } + add variantSets = "modelingVariant" +) +{ + float3[] extentsHint = [(-1.5, -1, -1.5), (1.5, 1, 1.5)] + + def Xform "Geom" + { + def Mesh "pSphere1" ( + hidden = true + ) + { + float3[] extent = [(-1, -1, -1), (1, 1, 1)] + int[] faceVertexCounts = [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3] + int[] faceVertexIndices = [0, 1, 21, 20, 1, 2, 22, 21, 2, 3, 23, 22, 3, 4, 24, 23, 4, 5, 25, 24, 5, 6, 26, 25, 6, 7, 27, 26, 7, 8, 28, 27, 8, 9, 29, 28, 9, 10, 30, 29, 10, 11, 31, 30, 11, 12, 32, 31, 12, 13, 33, 32, 13, 14, 34, 33, 14, 15, 35, 34, 15, 16, 36, 35, 16, 17, 37, 36, 17, 18, 38, 37, 18, 19, 39, 38, 19, 0, 20, 39, 20, 21, 41, 40, 21, 22, 42, 41, 22, 23, 43, 42, 23, 24, 44, 43, 24, 25, 45, 44, 25, 26, 46, 45, 26, 27, 47, 46, 27, 28, 48, 47, 28, 29, 49, 48, 29, 30, 50, 49, 30, 31, 51, 50, 31, 32, 52, 51, 32, 33, 53, 52, 33, 34, 54, 53, 34, 35, 55, 54, 35, 36, 56, 55, 36, 37, 57, 56, 37, 38, 58, 57, 38, 39, 59, 58, 39, 20, 40, 59, 40, 41, 61, 60, 41, 42, 62, 61, 42, 43, 63, 62, 43, 44, 64, 63, 44, 45, 65, 64, 45, 46, 66, 65, 46, 47, 67, 66, 47, 48, 68, 67, 48, 49, 69, 68, 49, 50, 70, 69, 50, 51, 71, 70, 51, 52, 72, 71, 52, 53, 73, 72, 53, 54, 74, 73, 54, 55, 75, 74, 55, 56, 76, 75, 56, 57, 77, 76, 57, 58, 78, 77, 58, 59, 79, 78, 59, 40, 60, 79, 60, 61, 81, 80, 61, 62, 82, 81, 62, 63, 83, 82, 63, 64, 84, 83, 64, 65, 85, 84, 65, 66, 86, 85, 66, 67, 87, 86, 67, 68, 88, 87, 68, 69, 89, 88, 69, 70, 90, 89, 70, 71, 91, 90, 71, 72, 92, 91, 72, 73, 93, 92, 73, 74, 94, 93, 74, 75, 95, 94, 75, 76, 96, 95, 76, 77, 97, 96, 77, 78, 98, 97, 78, 79, 99, 98, 79, 60, 80, 99, 80, 81, 101, 100, 81, 82, 102, 101, 82, 83, 103, 102, 83, 84, 104, 103, 84, 85, 105, 104, 85, 86, 106, 105, 86, 87, 107, 106, 87, 88, 108, 107, 88, 89, 109, 108, 89, 90, 110, 109, 90, 91, 111, 110, 91, 92, 112, 111, 92, 93, 113, 112, 93, 94, 114, 113, 94, 95, 115, 114, 95, 96, 116, 115, 96, 97, 117, 116, 97, 98, 118, 117, 98, 99, 119, 118, 99, 80, 100, 119, 100, 101, 121, 120, 101, 102, 122, 121, 102, 103, 123, 122, 103, 104, 124, 123, 104, 105, 125, 124, 105, 106, 126, 125, 106, 107, 127, 126, 107, 108, 128, 127, 108, 109, 129, 128, 109, 110, 130, 129, 110, 111, 131, 130, 111, 112, 132, 131, 112, 113, 133, 132, 113, 114, 134, 133, 114, 115, 135, 134, 115, 116, 136, 135, 116, 117, 137, 136, 117, 118, 138, 137, 118, 119, 139, 138, 119, 100, 120, 139, 120, 121, 141, 140, 121, 122, 142, 141, 122, 123, 143, 142, 123, 124, 144, 143, 124, 125, 145, 144, 125, 126, 146, 145, 126, 127, 147, 146, 127, 128, 148, 147, 128, 129, 149, 148, 129, 130, 150, 149, 130, 131, 151, 150, 131, 132, 152, 151, 132, 133, 153, 152, 133, 134, 154, 153, 134, 135, 155, 154, 135, 136, 156, 155, 136, 137, 157, 156, 137, 138, 158, 157, 138, 139, 159, 158, 139, 120, 140, 159, 140, 141, 161, 160, 141, 142, 162, 161, 142, 143, 163, 162, 143, 144, 164, 163, 144, 145, 165, 164, 145, 146, 166, 165, 146, 147, 167, 166, 147, 148, 168, 167, 148, 149, 169, 168, 149, 150, 170, 169, 150, 151, 171, 170, 151, 152, 172, 171, 152, 153, 173, 172, 153, 154, 174, 173, 154, 155, 175, 174, 155, 156, 176, 175, 156, 157, 177, 176, 157, 158, 178, 177, 158, 159, 179, 178, 159, 140, 160, 179, 160, 161, 181, 180, 161, 162, 182, 181, 162, 163, 183, 182, 163, 164, 184, 183, 164, 165, 185, 184, 165, 166, 186, 185, 166, 167, 187, 186, 167, 168, 188, 187, 168, 169, 189, 188, 169, 170, 190, 189, 170, 171, 191, 190, 171, 172, 192, 191, 172, 173, 193, 192, 173, 174, 194, 193, 174, 175, 195, 194, 175, 176, 196, 195, 176, 177, 197, 196, 177, 178, 198, 197, 178, 179, 199, 198, 179, 160, 180, 199, 180, 181, 201, 200, 181, 182, 202, 201, 182, 183, 203, 202, 183, 184, 204, 203, 184, 185, 205, 204, 185, 186, 206, 205, 186, 187, 207, 206, 187, 188, 208, 207, 188, 189, 209, 208, 189, 190, 210, 209, 190, 191, 211, 210, 191, 192, 212, 211, 192, 193, 213, 212, 193, 194, 214, 213, 194, 195, 215, 214, 195, 196, 216, 215, 196, 197, 217, 216, 197, 198, 218, 217, 198, 199, 219, 218, 199, 180, 200, 219, 200, 201, 221, 220, 201, 202, 222, 221, 202, 203, 223, 222, 203, 204, 224, 223, 204, 205, 225, 224, 205, 206, 226, 225, 206, 207, 227, 226, 207, 208, 228, 227, 208, 209, 229, 228, 209, 210, 230, 229, 210, 211, 231, 230, 211, 212, 232, 231, 212, 213, 233, 232, 213, 214, 234, 233, 214, 215, 235, 234, 215, 216, 236, 235, 216, 217, 237, 236, 217, 218, 238, 237, 218, 219, 239, 238, 219, 200, 220, 239, 220, 221, 241, 240, 221, 222, 242, 241, 222, 223, 243, 242, 223, 224, 244, 243, 224, 225, 245, 244, 225, 226, 246, 245, 226, 227, 247, 246, 227, 228, 248, 247, 228, 229, 249, 248, 229, 230, 250, 249, 230, 231, 251, 250, 231, 232, 252, 251, 232, 233, 253, 252, 233, 234, 254, 253, 234, 235, 255, 254, 235, 236, 256, 255, 236, 237, 257, 256, 237, 238, 258, 257, 238, 239, 259, 258, 239, 220, 240, 259, 240, 241, 261, 260, 241, 242, 262, 261, 242, 243, 263, 262, 243, 244, 264, 263, 244, 245, 265, 264, 245, 246, 266, 265, 246, 247, 267, 266, 247, 248, 268, 267, 248, 249, 269, 268, 249, 250, 270, 269, 250, 251, 271, 270, 251, 252, 272, 271, 252, 253, 273, 272, 253, 254, 274, 273, 254, 255, 275, 274, 255, 256, 276, 275, 256, 257, 277, 276, 257, 258, 278, 277, 258, 259, 279, 278, 259, 240, 260, 279, 260, 261, 281, 280, 261, 262, 282, 281, 262, 263, 283, 282, 263, 264, 284, 283, 264, 265, 285, 284, 265, 266, 286, 285, 266, 267, 287, 286, 267, 268, 288, 287, 268, 269, 289, 288, 269, 270, 290, 289, 270, 271, 291, 290, 271, 272, 292, 291, 272, 273, 293, 292, 273, 274, 294, 293, 274, 275, 295, 294, 275, 276, 296, 295, 276, 277, 297, 296, 277, 278, 298, 297, 278, 279, 299, 298, 279, 260, 280, 299, 280, 281, 301, 300, 281, 282, 302, 301, 282, 283, 303, 302, 283, 284, 304, 303, 284, 285, 305, 304, 285, 286, 306, 305, 286, 287, 307, 306, 287, 288, 308, 307, 288, 289, 309, 308, 289, 290, 310, 309, 290, 291, 311, 310, 291, 292, 312, 311, 292, 293, 313, 312, 293, 294, 314, 313, 294, 295, 315, 314, 295, 296, 316, 315, 296, 297, 317, 316, 297, 298, 318, 317, 298, 299, 319, 318, 299, 280, 300, 319, 300, 301, 321, 320, 301, 302, 322, 321, 302, 303, 323, 322, 303, 304, 324, 323, 304, 305, 325, 324, 305, 306, 326, 325, 306, 307, 327, 326, 307, 308, 328, 327, 308, 309, 329, 328, 309, 310, 330, 329, 310, 311, 331, 330, 311, 312, 332, 331, 312, 313, 333, 332, 313, 314, 334, 333, 314, 315, 335, 334, 315, 316, 336, 335, 316, 317, 337, 336, 317, 318, 338, 337, 318, 319, 339, 338, 319, 300, 320, 339, 320, 321, 341, 340, 321, 322, 342, 341, 322, 323, 343, 342, 323, 324, 344, 343, 324, 325, 345, 344, 325, 326, 346, 345, 326, 327, 347, 346, 327, 328, 348, 347, 328, 329, 349, 348, 329, 330, 350, 349, 330, 331, 351, 350, 331, 332, 352, 351, 332, 333, 353, 352, 333, 334, 354, 353, 334, 335, 355, 354, 335, 336, 356, 355, 336, 337, 357, 356, 337, 338, 358, 357, 338, 339, 359, 358, 339, 320, 340, 359, 340, 341, 361, 360, 341, 342, 362, 361, 342, 343, 363, 362, 343, 344, 364, 363, 344, 345, 365, 364, 345, 346, 366, 365, 346, 347, 367, 366, 347, 348, 368, 367, 348, 349, 369, 368, 349, 350, 370, 369, 350, 351, 371, 370, 351, 352, 372, 371, 352, 353, 373, 372, 353, 354, 374, 373, 354, 355, 375, 374, 355, 356, 376, 375, 356, 357, 377, 376, 357, 358, 378, 377, 358, 359, 379, 378, 359, 340, 360, 379, 1, 0, 380, 2, 1, 380, 3, 2, 380, 4, 3, 380, 5, 4, 380, 6, 5, 380, 7, 6, 380, 8, 7, 380, 9, 8, 380, 10, 9, 380, 11, 10, 380, 12, 11, 380, 13, 12, 380, 14, 13, 380, 15, 14, 380, 16, 15, 380, 17, 16, 380, 18, 17, 380, 19, 18, 380, 0, 19, 380, 360, 361, 381, 361, 362, 381, 362, 363, 381, 363, 364, 381, 364, 365, 381, 365, 366, 381, 366, 367, 381, 367, 368, 381, 368, 369, 381, 369, 370, 381, 370, 371, 381, 371, 372, 381, 372, 373, 381, 373, 374, 381, 374, 375, 381, 375, 376, 381, 376, 377, 381, 377, 378, 381, 378, 379, 381, 379, 360, 381] + token interpolateBoundary = "edgeAndCorner" + uniform token orientation = "rightHanded" + float3[] points = [(0.148778, -0.987688, -0.0483409), (0.126558, -0.987688, -0.0919499), (0.0919499, -0.987688, -0.126558), (0.0483409, -0.987688, -0.148778), (0, -0.987688, -0.156435), (-0.0483409, -0.987688, -0.148778), (-0.0919499, -0.987688, -0.126558), (-0.126558, -0.987688, -0.0919499), (-0.148778, -0.987688, -0.0483409), (-0.156435, -0.987688, 0), (-0.148778, -0.987688, 0.0483409), (-0.126558, -0.987688, 0.0919499), (-0.0919499, -0.987688, 0.126558), (-0.0483409, -0.987688, 0.148778), (-4.66211e-09, -0.987688, 0.156434), (0.0483409, -0.987688, 0.148778), (0.0919499, -0.987688, 0.126558), (0.126558, -0.987688, 0.0919499), (0.148778, -0.987688, 0.0483409), (0.156434, -0.987688, 0), (0.293893, -0.951057, -0.0954916), (0.25, -0.951057, -0.181636), (0.181636, -0.951057, -0.25), (0.0954916, -0.951057, -0.293893), (0, -0.951057, -0.309017), (-0.0954916, -0.951057, -0.293893), (-0.181636, -0.951057, -0.25), (-0.25, -0.951057, -0.181636), (-0.293893, -0.951057, -0.0954915), (-0.309017, -0.951057, 0), (-0.293893, -0.951057, 0.0954915), (-0.25, -0.951057, 0.181636), (-0.181636, -0.951057, 0.25), (-0.0954915, -0.951057, 0.293893), (-9.20942e-09, -0.951057, 0.309017), (0.0954915, -0.951057, 0.293893), (0.181636, -0.951057, 0.25), (0.25, -0.951057, 0.181636), (0.293893, -0.951057, 0.0954915), (0.309017, -0.951057, 0), (0.431771, -0.891007, -0.140291), (0.367286, -0.891007, -0.266849), (0.266849, -0.891007, -0.367286), (0.140291, -0.891007, -0.431771), (0, -0.891007, -0.453991), (-0.140291, -0.891007, -0.431771), (-0.266849, -0.891007, -0.367286), (-0.367286, -0.891007, -0.266849), (-0.431771, -0.891007, -0.140291), (-0.453991, -0.891007, 0), (-0.431771, -0.891007, 0.140291), (-0.367286, -0.891007, 0.266849), (-0.266849, -0.891007, 0.367286), (-0.140291, -0.891007, 0.431771), (-1.353e-08, -0.891007, 0.453991), (0.140291, -0.891007, 0.431771), (0.266849, -0.891007, 0.367286), (0.367286, -0.891007, 0.266849), (0.431771, -0.891007, 0.140291), (0.453991, -0.891007, 0), (0.559017, -0.809017, -0.181636), (0.475529, -0.809017, -0.345492), (0.345492, -0.809017, -0.475529), (0.181636, -0.809017, -0.559017), (0, -0.809017, -0.587786), (-0.181636, -0.809017, -0.559017), (-0.345492, -0.809017, -0.475528), (-0.475528, -0.809017, -0.345492), (-0.559017, -0.809017, -0.181636), (-0.587785, -0.809017, 0), (-0.559017, -0.809017, 0.181636), (-0.475528, -0.809017, 0.345492), (-0.345492, -0.809017, 0.475528), (-0.181636, -0.809017, 0.559017), (-1.75174e-08, -0.809017, 0.587785), (0.181636, -0.809017, 0.559017), (0.345491, -0.809017, 0.475528), (0.475528, -0.809017, 0.345492), (0.559017, -0.809017, 0.181636), (0.587785, -0.809017, 0), (0.672499, -0.707107, -0.218508), (0.572062, -0.707107, -0.415627), (0.415627, -0.707107, -0.572062), (0.218508, -0.707107, -0.672499), (0, -0.707107, -0.707107), (-0.218508, -0.707107, -0.672499), (-0.415627, -0.707107, -0.572062), (-0.572062, -0.707107, -0.415627), (-0.672499, -0.707107, -0.218508), (-0.707107, -0.707107, 0), (-0.672499, -0.707107, 0.218508), (-0.572062, -0.707107, 0.415627), (-0.415627, -0.707107, 0.572061), (-0.218508, -0.707107, 0.672499), (-2.10734e-08, -0.707107, 0.707107), (0.218508, -0.707107, 0.672499), (0.415627, -0.707107, 0.572061), (0.572061, -0.707107, 0.415627), (0.672499, -0.707107, 0.218508), (0.707107, -0.707107, 0), (0.769421, -0.587785, -0.25), (0.654509, -0.587785, -0.475529), (0.475529, -0.587785, -0.654509), (0.25, -0.587785, -0.769421), (0, -0.587785, -0.809017), (-0.25, -0.587785, -0.769421), (-0.475528, -0.587785, -0.654509), (-0.654509, -0.587785, -0.475528), (-0.769421, -0.587785, -0.25), (-0.809017, -0.587785, 0), (-0.769421, -0.587785, 0.25), (-0.654509, -0.587785, 0.475528), (-0.475528, -0.587785, 0.654509), (-0.25, -0.587785, 0.769421), (-2.41106e-08, -0.587785, 0.809017), (0.25, -0.587785, 0.769421), (0.475528, -0.587785, 0.654509), (0.654509, -0.587785, 0.475528), (0.769421, -0.587785, 0.25), (0.809017, -0.587785, 0), (0.847398, -0.453991, -0.275336), (0.72084, -0.453991, -0.523721), (0.523721, -0.453991, -0.72084), (0.275336, -0.453991, -0.847398), (0, -0.453991, -0.891007), (-0.275336, -0.453991, -0.847398), (-0.523721, -0.453991, -0.72084), (-0.72084, -0.453991, -0.523721), (-0.847398, -0.453991, -0.275336), (-0.891007, -0.453991, 0), (-0.847398, -0.453991, 0.275336), (-0.72084, -0.453991, 0.523721), (-0.523721, -0.453991, 0.72084), (-0.275336, -0.453991, 0.847398), (-2.65541e-08, -0.453991, 0.891007), (0.275336, -0.453991, 0.847398), (0.523721, -0.453991, 0.72084), (0.720839, -0.453991, 0.523721), (0.847398, -0.453991, 0.275336), (0.891007, -0.453991, 0), (0.904509, -0.309017, -0.293893), (0.769421, -0.309017, -0.559017), (0.559017, -0.309017, -0.769421), (0.293893, -0.309017, -0.904509), (0, -0.309017, -0.951057), (-0.293893, -0.309017, -0.904509), (-0.559017, -0.309017, -0.769421), (-0.769421, -0.309017, -0.559017), (-0.904509, -0.309017, -0.293893), (-0.951057, -0.309017, 0), (-0.904509, -0.309017, 0.293893), (-0.769421, -0.309017, 0.559017), (-0.559017, -0.309017, 0.769421), (-0.293893, -0.309017, 0.904509), (-2.83437e-08, -0.309017, 0.951057), (0.293893, -0.309017, 0.904509), (0.559017, -0.309017, 0.769421), (0.769421, -0.309017, 0.559017), (0.904509, -0.309017, 0.293893), (0.951057, -0.309017, 0), (0.939348, -0.156434, -0.305213), (0.799057, -0.156434, -0.580549), (0.580549, -0.156434, -0.799057), (0.305213, -0.156434, -0.939348), (0, -0.156434, -0.987689), (-0.305213, -0.156434, -0.939348), (-0.580549, -0.156434, -0.799057), (-0.799057, -0.156434, -0.580549), (-0.939348, -0.156434, -0.305213), (-0.987689, -0.156434, 0), (-0.939348, -0.156434, 0.305213), (-0.799057, -0.156434, 0.580549), (-0.580549, -0.156434, 0.799057), (-0.305213, -0.156434, 0.939348), (-2.94354e-08, -0.156434, 0.987688), (0.305212, -0.156434, 0.939348), (0.580549, -0.156434, 0.799057), (0.799057, -0.156434, 0.580549), (0.939348, -0.156434, 0.305212), (0.987688, -0.156434, 0), (0.951057, 0, -0.309017), (0.809018, 0, -0.587786), (0.587786, 0, -0.809017), (0.309017, 0, -0.951057), (0, 0, -1), (-0.309017, 0, -0.951057), (-0.587785, 0, -0.809017), (-0.809017, 0, -0.587785), (-0.951057, 0, -0.309017), (-1, 0, 0), (-0.951057, 0, 0.309017), (-0.809017, 0, 0.587785), (-0.587785, 0, 0.809017), (-0.309017, 0, 0.951057), (-2.98023e-08, 0, 1), (0.309017, 0, 0.951057), (0.587785, 0, 0.809017), (0.809017, 0, 0.587785), (0.951057, 0, 0.309017), (1, 0, 0), (0.939348, 0.156434, -0.305213), (0.799057, 0.156434, -0.580549), (0.580549, 0.156434, -0.799057), (0.305213, 0.156434, -0.939348), (0, 0.156434, -0.987689), (-0.305213, 0.156434, -0.939348), (-0.580549, 0.156434, -0.799057), (-0.799057, 0.156434, -0.580549), (-0.939348, 0.156434, -0.305213), (-0.987689, 0.156434, 0), (-0.939348, 0.156434, 0.305213), (-0.799057, 0.156434, 0.580549), (-0.580549, 0.156434, 0.799057), (-0.305213, 0.156434, 0.939348), (-2.94354e-08, 0.156434, 0.987688), (0.305212, 0.156434, 0.939348), (0.580549, 0.156434, 0.799057), (0.799057, 0.156434, 0.580549), (0.939348, 0.156434, 0.305212), (0.987688, 0.156434, 0), (0.904509, 0.309017, -0.293893), (0.769421, 0.309017, -0.559017), (0.559017, 0.309017, -0.769421), (0.293893, 0.309017, -0.904509), (0, 0.309017, -0.951057), (-0.293893, 0.309017, -0.904509), (-0.559017, 0.309017, -0.769421), (-0.769421, 0.309017, -0.559017), (-0.904509, 0.309017, -0.293893), (-0.951057, 0.309017, 0), (-0.904509, 0.309017, 0.293893), (-0.769421, 0.309017, 0.559017), (-0.559017, 0.309017, 0.769421), (-0.293893, 0.309017, 0.904509), (-2.83437e-08, 0.309017, 0.951057), (0.293893, 0.309017, 0.904509), (0.559017, 0.309017, 0.769421), (0.769421, 0.309017, 0.559017), (0.904509, 0.309017, 0.293893), (0.951057, 0.309017, 0), (0.847398, 0.453991, -0.275336), (0.72084, 0.453991, -0.523721), (0.523721, 0.453991, -0.72084), (0.275336, 0.453991, -0.847398), (0, 0.453991, -0.891007), (-0.275336, 0.453991, -0.847398), (-0.523721, 0.453991, -0.72084), (-0.72084, 0.453991, -0.523721), (-0.847398, 0.453991, -0.275336), (-0.891007, 0.453991, 0), (-0.847398, 0.453991, 0.275336), (-0.72084, 0.453991, 0.523721), (-0.523721, 0.453991, 0.72084), (-0.275336, 0.453991, 0.847398), (-2.65541e-08, 0.453991, 0.891007), (0.275336, 0.453991, 0.847398), (0.523721, 0.453991, 0.72084), (0.720839, 0.453991, 0.523721), (0.847398, 0.453991, 0.275336), (0.891007, 0.453991, 0), (0.769421, 0.587785, -0.25), (0.654509, 0.587785, -0.475529), (0.475529, 0.587785, -0.654509), (0.25, 0.587785, -0.769421), (0, 0.587785, -0.809017), (-0.25, 0.587785, -0.769421), (-0.475528, 0.587785, -0.654509), (-0.654509, 0.587785, -0.475528), (-0.769421, 0.587785, -0.25), (-0.809017, 0.587785, 0), (-0.769421, 0.587785, 0.25), (-0.654509, 0.587785, 0.475528), (-0.475528, 0.587785, 0.654509), (-0.25, 0.587785, 0.769421), (-2.41106e-08, 0.587785, 0.809017), (0.25, 0.587785, 0.769421), (0.475528, 0.587785, 0.654509), (0.654509, 0.587785, 0.475528), (0.769421, 0.587785, 0.25), (0.809017, 0.587785, 0), (0.672499, 0.707107, -0.218508), (0.572062, 0.707107, -0.415627), (0.415627, 0.707107, -0.572062), (0.218508, 0.707107, -0.672499), (0, 0.707107, -0.707107), (-0.218508, 0.707107, -0.672499), (-0.415627, 0.707107, -0.572062), (-0.572062, 0.707107, -0.415627), (-0.672499, 0.707107, -0.218508), (-0.707107, 0.707107, 0), (-0.672499, 0.707107, 0.218508), (-0.572062, 0.707107, 0.415627), (-0.415627, 0.707107, 0.572061), (-0.218508, 0.707107, 0.672499), (-2.10734e-08, 0.707107, 0.707107), (0.218508, 0.707107, 0.672499), (0.415627, 0.707107, 0.572061), (0.572061, 0.707107, 0.415627), (0.672499, 0.707107, 0.218508), (0.707107, 0.707107, 0), (0.559017, 0.809017, -0.181636), (0.475529, 0.809017, -0.345492), (0.345492, 0.809017, -0.475529), (0.181636, 0.809017, -0.559017), (0, 0.809017, -0.587786), (-0.181636, 0.809017, -0.559017), (-0.345492, 0.809017, -0.475528), (-0.475528, 0.809017, -0.345492), (-0.559017, 0.809017, -0.181636), (-0.587785, 0.809017, 0), (-0.559017, 0.809017, 0.181636), (-0.475528, 0.809017, 0.345492), (-0.345492, 0.809017, 0.475528), (-0.181636, 0.809017, 0.559017), (-1.75174e-08, 0.809017, 0.587785), (0.181636, 0.809017, 0.559017), (0.345491, 0.809017, 0.475528), (0.475528, 0.809017, 0.345492), (0.559017, 0.809017, 0.181636), (0.587785, 0.809017, 0), (0.431771, 0.891007, -0.140291), (0.367286, 0.891007, -0.266849), (0.266849, 0.891007, -0.367286), (0.140291, 0.891007, -0.431771), (0, 0.891007, -0.453991), (-0.140291, 0.891007, -0.431771), (-0.266849, 0.891007, -0.367286), (-0.367286, 0.891007, -0.266849), (-0.431771, 0.891007, -0.140291), (-0.453991, 0.891007, 0), (-0.431771, 0.891007, 0.140291), (-0.367286, 0.891007, 0.266849), (-0.266849, 0.891007, 0.367286), (-0.140291, 0.891007, 0.431771), (-1.353e-08, 0.891007, 0.453991), (0.140291, 0.891007, 0.431771), (0.266849, 0.891007, 0.367286), (0.367286, 0.891007, 0.266849), (0.431771, 0.891007, 0.140291), (0.453991, 0.891007, 0), (0.293893, 0.951057, -0.0954916), (0.25, 0.951057, -0.181636), (0.181636, 0.951057, -0.25), (0.0954916, 0.951057, -0.293893), (0, 0.951057, -0.309017), (-0.0954916, 0.951057, -0.293893), (-0.181636, 0.951057, -0.25), (-0.25, 0.951057, -0.181636), (-0.293893, 0.951057, -0.0954915), (-0.309017, 0.951057, 0), (-0.293893, 0.951057, 0.0954915), (-0.25, 0.951057, 0.181636), (-0.181636, 0.951057, 0.25), (-0.0954915, 0.951057, 0.293893), (-9.20942e-09, 0.951057, 0.309017), (0.0954915, 0.951057, 0.293893), (0.181636, 0.951057, 0.25), (0.25, 0.951057, 0.181636), (0.293893, 0.951057, 0.0954915), (0.309017, 0.951057, 0), (0.148778, 0.987688, -0.0483409), (0.126558, 0.987688, -0.0919499), (0.0919499, 0.987688, -0.126558), (0.0483409, 0.987688, -0.148778), (0, 0.987688, -0.156435), (-0.0483409, 0.987688, -0.148778), (-0.0919499, 0.987688, -0.126558), (-0.126558, 0.987688, -0.0919499), (-0.148778, 0.987688, -0.0483409), (-0.156435, 0.987688, 0), (-0.148778, 0.987688, 0.0483409), (-0.126558, 0.987688, 0.0919499), (-0.0919499, 0.987688, 0.126558), (-0.0483409, 0.987688, 0.148778), (-4.66211e-09, 0.987688, 0.156434), (0.0483409, 0.987688, 0.148778), (0.0919499, 0.987688, 0.126558), (0.126558, 0.987688, 0.0919499), (0.148778, 0.987688, 0.0483409), (0.156434, 0.987688, 0), (0, -1, 0), (0, 1, 0)] + string primvars:__handleid = "${user:ModelInstance}_pSphere1" ( + interpolation = "constant" + ) + color3f[] primvars:displayColor = [(0.217638, 0.217638, 0.217638)] + float3[] primvars:ModelBuildRefPose = [(0.148778, -0.987688, -0.0483409), (0.126558, -0.987688, -0.0919499), (0.0919499, -0.987688, -0.126558), (0.0483409, -0.987688, -0.148778), (0, -0.987688, -0.156435), (-0.0483409, -0.987688, -0.148778), (-0.0919499, -0.987688, -0.126558), (-0.126558, -0.987688, -0.0919499), (-0.148778, -0.987688, -0.0483409), (-0.156435, -0.987688, 0), (-0.148778, -0.987688, 0.0483409), (-0.126558, -0.987688, 0.0919499), (-0.0919499, -0.987688, 0.126558), (-0.0483409, -0.987688, 0.148778), (-4.66211e-09, -0.987688, 0.156434), (0.0483409, -0.987688, 0.148778), (0.0919499, -0.987688, 0.126558), (0.126558, -0.987688, 0.0919499), (0.148778, -0.987688, 0.0483409), (0.156434, -0.987688, 0), (0.293893, -0.951057, -0.0954916), (0.25, -0.951057, -0.181636), (0.181636, -0.951057, -0.25), (0.0954916, -0.951057, -0.293893), (0, -0.951057, -0.309017), (-0.0954916, -0.951057, -0.293893), (-0.181636, -0.951057, -0.25), (-0.25, -0.951057, -0.181636), (-0.293893, -0.951057, -0.0954915), (-0.309017, -0.951057, 0), (-0.293893, -0.951057, 0.0954915), (-0.25, -0.951057, 0.181636), (-0.181636, -0.951057, 0.25), (-0.0954915, -0.951057, 0.293893), (-9.20942e-09, -0.951057, 0.309017), (0.0954915, -0.951057, 0.293893), (0.181636, -0.951057, 0.25), (0.25, -0.951057, 0.181636), (0.293893, -0.951057, 0.0954915), (0.309017, -0.951057, 0), (0.431771, -0.891007, -0.140291), (0.367286, -0.891007, -0.266849), (0.266849, -0.891007, -0.367286), (0.140291, -0.891007, -0.431771), (0, -0.891007, -0.453991), (-0.140291, -0.891007, -0.431771), (-0.266849, -0.891007, -0.367286), (-0.367286, -0.891007, -0.266849), (-0.431771, -0.891007, -0.140291), (-0.453991, -0.891007, 0), (-0.431771, -0.891007, 0.140291), (-0.367286, -0.891007, 0.266849), (-0.266849, -0.891007, 0.367286), (-0.140291, -0.891007, 0.431771), (-1.353e-08, -0.891007, 0.453991), (0.140291, -0.891007, 0.431771), (0.266849, -0.891007, 0.367286), (0.367286, -0.891007, 0.266849), (0.431771, -0.891007, 0.140291), (0.453991, -0.891007, 0), (0.559017, -0.809017, -0.181636), (0.475529, -0.809017, -0.345492), (0.345492, -0.809017, -0.475529), (0.181636, -0.809017, -0.559017), (0, -0.809017, -0.587786), (-0.181636, -0.809017, -0.559017), (-0.345492, -0.809017, -0.475528), (-0.475528, -0.809017, -0.345492), (-0.559017, -0.809017, -0.181636), (-0.587785, -0.809017, 0), (-0.559017, -0.809017, 0.181636), (-0.475528, -0.809017, 0.345492), (-0.345492, -0.809017, 0.475528), (-0.181636, -0.809017, 0.559017), (-1.75174e-08, -0.809017, 0.587785), (0.181636, -0.809017, 0.559017), (0.345491, -0.809017, 0.475528), (0.475528, -0.809017, 0.345492), (0.559017, -0.809017, 0.181636), (0.587785, -0.809017, 0), (0.672499, -0.707107, -0.218508), (0.572062, -0.707107, -0.415627), (0.415627, -0.707107, -0.572062), (0.218508, -0.707107, -0.672499), (0, -0.707107, -0.707107), (-0.218508, -0.707107, -0.672499), (-0.415627, -0.707107, -0.572062), (-0.572062, -0.707107, -0.415627), (-0.672499, -0.707107, -0.218508), (-0.707107, -0.707107, 0), (-0.672499, -0.707107, 0.218508), (-0.572062, -0.707107, 0.415627), (-0.415627, -0.707107, 0.572061), (-0.218508, -0.707107, 0.672499), (-2.10734e-08, -0.707107, 0.707107), (0.218508, -0.707107, 0.672499), (0.415627, -0.707107, 0.572061), (0.572061, -0.707107, 0.415627), (0.672499, -0.707107, 0.218508), (0.707107, -0.707107, 0), (0.769421, -0.587785, -0.25), (0.654509, -0.587785, -0.475529), (0.475529, -0.587785, -0.654509), (0.25, -0.587785, -0.769421), (0, -0.587785, -0.809017), (-0.25, -0.587785, -0.769421), (-0.475528, -0.587785, -0.654509), (-0.654509, -0.587785, -0.475528), (-0.769421, -0.587785, -0.25), (-0.809017, -0.587785, 0), (-0.769421, -0.587785, 0.25), (-0.654509, -0.587785, 0.475528), (-0.475528, -0.587785, 0.654509), (-0.25, -0.587785, 0.769421), (-2.41106e-08, -0.587785, 0.809017), (0.25, -0.587785, 0.769421), (0.475528, -0.587785, 0.654509), (0.654509, -0.587785, 0.475528), (0.769421, -0.587785, 0.25), (0.809017, -0.587785, 0), (0.847398, -0.453991, -0.275336), (0.72084, -0.453991, -0.523721), (0.523721, -0.453991, -0.72084), (0.275336, -0.453991, -0.847398), (0, -0.453991, -0.891007), (-0.275336, -0.453991, -0.847398), (-0.523721, -0.453991, -0.72084), (-0.72084, -0.453991, -0.523721), (-0.847398, -0.453991, -0.275336), (-0.891007, -0.453991, 0), (-0.847398, -0.453991, 0.275336), (-0.72084, -0.453991, 0.523721), (-0.523721, -0.453991, 0.72084), (-0.275336, -0.453991, 0.847398), (-2.65541e-08, -0.453991, 0.891007), (0.275336, -0.453991, 0.847398), (0.523721, -0.453991, 0.72084), (0.720839, -0.453991, 0.523721), (0.847398, -0.453991, 0.275336), (0.891007, -0.453991, 0), (0.904509, -0.309017, -0.293893), (0.769421, -0.309017, -0.559017), (0.559017, -0.309017, -0.769421), (0.293893, -0.309017, -0.904509), (0, -0.309017, -0.951057), (-0.293893, -0.309017, -0.904509), (-0.559017, -0.309017, -0.769421), (-0.769421, -0.309017, -0.559017), (-0.904509, -0.309017, -0.293893), (-0.951057, -0.309017, 0), (-0.904509, -0.309017, 0.293893), (-0.769421, -0.309017, 0.559017), (-0.559017, -0.309017, 0.769421), (-0.293893, -0.309017, 0.904509), (-2.83437e-08, -0.309017, 0.951057), (0.293893, -0.309017, 0.904509), (0.559017, -0.309017, 0.769421), (0.769421, -0.309017, 0.559017), (0.904509, -0.309017, 0.293893), (0.951057, -0.309017, 0), (0.939348, -0.156434, -0.305213), (0.799057, -0.156434, -0.580549), (0.580549, -0.156434, -0.799057), (0.305213, -0.156434, -0.939348), (0, -0.156434, -0.987689), (-0.305213, -0.156434, -0.939348), (-0.580549, -0.156434, -0.799057), (-0.799057, -0.156434, -0.580549), (-0.939348, -0.156434, -0.305213), (-0.987689, -0.156434, 0), (-0.939348, -0.156434, 0.305213), (-0.799057, -0.156434, 0.580549), (-0.580549, -0.156434, 0.799057), (-0.305213, -0.156434, 0.939348), (-2.94354e-08, -0.156434, 0.987688), (0.305212, -0.156434, 0.939348), (0.580549, -0.156434, 0.799057), (0.799057, -0.156434, 0.580549), (0.939348, -0.156434, 0.305212), (0.987688, -0.156434, 0), (0.951057, 0, -0.309017), (0.809018, 0, -0.587786), (0.587786, 0, -0.809017), (0.309017, 0, -0.951057), (0, 0, -1), (-0.309017, 0, -0.951057), (-0.587785, 0, -0.809017), (-0.809017, 0, -0.587785), (-0.951057, 0, -0.309017), (-1, 0, 0), (-0.951057, 0, 0.309017), (-0.809017, 0, 0.587785), (-0.587785, 0, 0.809017), (-0.309017, 0, 0.951057), (-2.98023e-08, 0, 1), (0.309017, 0, 0.951057), (0.587785, 0, 0.809017), (0.809017, 0, 0.587785), (0.951057, 0, 0.309017), (1, 0, 0), (0.939348, 0.156434, -0.305213), (0.799057, 0.156434, -0.580549), (0.580549, 0.156434, -0.799057), (0.305213, 0.156434, -0.939348), (0, 0.156434, -0.987689), (-0.305213, 0.156434, -0.939348), (-0.580549, 0.156434, -0.799057), (-0.799057, 0.156434, -0.580549), (-0.939348, 0.156434, -0.305213), (-0.987689, 0.156434, 0), (-0.939348, 0.156434, 0.305213), (-0.799057, 0.156434, 0.580549), (-0.580549, 0.156434, 0.799057), (-0.305213, 0.156434, 0.939348), (-2.94354e-08, 0.156434, 0.987688), (0.305212, 0.156434, 0.939348), (0.580549, 0.156434, 0.799057), (0.799057, 0.156434, 0.580549), (0.939348, 0.156434, 0.305212), (0.987688, 0.156434, 0), (0.904509, 0.309017, -0.293893), (0.769421, 0.309017, -0.559017), (0.559017, 0.309017, -0.769421), (0.293893, 0.309017, -0.904509), (0, 0.309017, -0.951057), (-0.293893, 0.309017, -0.904509), (-0.559017, 0.309017, -0.769421), (-0.769421, 0.309017, -0.559017), (-0.904509, 0.309017, -0.293893), (-0.951057, 0.309017, 0), (-0.904509, 0.309017, 0.293893), (-0.769421, 0.309017, 0.559017), (-0.559017, 0.309017, 0.769421), (-0.293893, 0.309017, 0.904509), (-2.83437e-08, 0.309017, 0.951057), (0.293893, 0.309017, 0.904509), (0.559017, 0.309017, 0.769421), (0.769421, 0.309017, 0.559017), (0.904509, 0.309017, 0.293893), (0.951057, 0.309017, 0), (0.847398, 0.453991, -0.275336), (0.72084, 0.453991, -0.523721), (0.523721, 0.453991, -0.72084), (0.275336, 0.453991, -0.847398), (0, 0.453991, -0.891007), (-0.275336, 0.453991, -0.847398), (-0.523721, 0.453991, -0.72084), (-0.72084, 0.453991, -0.523721), (-0.847398, 0.453991, -0.275336), (-0.891007, 0.453991, 0), (-0.847398, 0.453991, 0.275336), (-0.72084, 0.453991, 0.523721), (-0.523721, 0.453991, 0.72084), (-0.275336, 0.453991, 0.847398), (-2.65541e-08, 0.453991, 0.891007), (0.275336, 0.453991, 0.847398), (0.523721, 0.453991, 0.72084), (0.720839, 0.453991, 0.523721), (0.847398, 0.453991, 0.275336), (0.891007, 0.453991, 0), (0.769421, 0.587785, -0.25), (0.654509, 0.587785, -0.475529), (0.475529, 0.587785, -0.654509), (0.25, 0.587785, -0.769421), (0, 0.587785, -0.809017), (-0.25, 0.587785, -0.769421), (-0.475528, 0.587785, -0.654509), (-0.654509, 0.587785, -0.475528), (-0.769421, 0.587785, -0.25), (-0.809017, 0.587785, 0), (-0.769421, 0.587785, 0.25), (-0.654509, 0.587785, 0.475528), (-0.475528, 0.587785, 0.654509), (-0.25, 0.587785, 0.769421), (-2.41106e-08, 0.587785, 0.809017), (0.25, 0.587785, 0.769421), (0.475528, 0.587785, 0.654509), (0.654509, 0.587785, 0.475528), (0.769421, 0.587785, 0.25), (0.809017, 0.587785, 0), (0.672499, 0.707107, -0.218508), (0.572062, 0.707107, -0.415627), (0.415627, 0.707107, -0.572062), (0.218508, 0.707107, -0.672499), (0, 0.707107, -0.707107), (-0.218508, 0.707107, -0.672499), (-0.415627, 0.707107, -0.572062), (-0.572062, 0.707107, -0.415627), (-0.672499, 0.707107, -0.218508), (-0.707107, 0.707107, 0), (-0.672499, 0.707107, 0.218508), (-0.572062, 0.707107, 0.415627), (-0.415627, 0.707107, 0.572061), (-0.218508, 0.707107, 0.672499), (-2.10734e-08, 0.707107, 0.707107), (0.218508, 0.707107, 0.672499), (0.415627, 0.707107, 0.572061), (0.572061, 0.707107, 0.415627), (0.672499, 0.707107, 0.218508), (0.707107, 0.707107, 0), (0.559017, 0.809017, -0.181636), (0.475529, 0.809017, -0.345492), (0.345492, 0.809017, -0.475529), (0.181636, 0.809017, -0.559017), (0, 0.809017, -0.587786), (-0.181636, 0.809017, -0.559017), (-0.345492, 0.809017, -0.475528), (-0.475528, 0.809017, -0.345492), (-0.559017, 0.809017, -0.181636), (-0.587785, 0.809017, 0), (-0.559017, 0.809017, 0.181636), (-0.475528, 0.809017, 0.345492), (-0.345492, 0.809017, 0.475528), (-0.181636, 0.809017, 0.559017), (-1.75174e-08, 0.809017, 0.587785), (0.181636, 0.809017, 0.559017), (0.345491, 0.809017, 0.475528), (0.475528, 0.809017, 0.345492), (0.559017, 0.809017, 0.181636), (0.587785, 0.809017, 0), (0.431771, 0.891007, -0.140291), (0.367286, 0.891007, -0.266849), (0.266849, 0.891007, -0.367286), (0.140291, 0.891007, -0.431771), (0, 0.891007, -0.453991), (-0.140291, 0.891007, -0.431771), (-0.266849, 0.891007, -0.367286), (-0.367286, 0.891007, -0.266849), (-0.431771, 0.891007, -0.140291), (-0.453991, 0.891007, 0), (-0.431771, 0.891007, 0.140291), (-0.367286, 0.891007, 0.266849), (-0.266849, 0.891007, 0.367286), (-0.140291, 0.891007, 0.431771), (-1.353e-08, 0.891007, 0.453991), (0.140291, 0.891007, 0.431771), (0.266849, 0.891007, 0.367286), (0.367286, 0.891007, 0.266849), (0.431771, 0.891007, 0.140291), (0.453991, 0.891007, 0), (0.293893, 0.951057, -0.0954916), (0.25, 0.951057, -0.181636), (0.181636, 0.951057, -0.25), (0.0954916, 0.951057, -0.293893), (0, 0.951057, -0.309017), (-0.0954916, 0.951057, -0.293893), (-0.181636, 0.951057, -0.25), (-0.25, 0.951057, -0.181636), (-0.293893, 0.951057, -0.0954915), (-0.309017, 0.951057, 0), (-0.293893, 0.951057, 0.0954915), (-0.25, 0.951057, 0.181636), (-0.181636, 0.951057, 0.25), (-0.0954915, 0.951057, 0.293893), (-9.20942e-09, 0.951057, 0.309017), (0.0954915, 0.951057, 0.293893), (0.181636, 0.951057, 0.25), (0.25, 0.951057, 0.181636), (0.293893, 0.951057, 0.0954915), (0.309017, 0.951057, 0), (0.148778, 0.987688, -0.0483409), (0.126558, 0.987688, -0.0919499), (0.0919499, 0.987688, -0.126558), (0.0483409, 0.987688, -0.148778), (0, 0.987688, -0.156435), (-0.0483409, 0.987688, -0.148778), (-0.0919499, 0.987688, -0.126558), (-0.126558, 0.987688, -0.0919499), (-0.148778, 0.987688, -0.0483409), (-0.156435, 0.987688, 0), (-0.148778, 0.987688, 0.0483409), (-0.126558, 0.987688, 0.0919499), (-0.0919499, 0.987688, 0.126558), (-0.0483409, 0.987688, 0.148778), (-4.66211e-09, 0.987688, 0.156434), (0.0483409, 0.987688, 0.148778), (0.0919499, 0.987688, 0.126558), (0.126558, 0.987688, 0.0919499), (0.148778, 0.987688, 0.0483409), (0.156434, 0.987688, 0), (0, -1, 0), (0, 1, 0)] ( + interpolation = "vertex" + ) + float[] primvars:ptexFaceIndex = [0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63, 64, 64, 64, 64, 65, 65, 65, 65, 66, 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 69, 69, 69, 70, 70, 70, 70, 71, 71, 71, 71, 72, 72, 72, 72, 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, 77, 78, 78, 78, 78, 79, 79, 79, 79, 80, 80, 80, 80, 81, 81, 81, 81, 82, 82, 82, 82, 83, 83, 83, 83, 84, 84, 84, 84, 85, 85, 85, 85, 86, 86, 86, 86, 87, 87, 87, 87, 88, 88, 88, 88, 89, 89, 89, 89, 90, 90, 90, 90, 91, 91, 91, 91, 92, 92, 92, 92, 93, 93, 93, 93, 94, 94, 94, 94, 95, 95, 95, 95, 96, 96, 96, 96, 97, 97, 97, 97, 98, 98, 98, 98, 99, 99, 99, 99, 100, 100, 100, 100, 101, 101, 101, 101, 102, 102, 102, 102, 103, 103, 103, 103, 104, 104, 104, 104, 105, 105, 105, 105, 106, 106, 106, 106, 107, 107, 107, 107, 108, 108, 108, 108, 109, 109, 109, 109, 110, 110, 110, 110, 111, 111, 111, 111, 112, 112, 112, 112, 113, 113, 113, 113, 114, 114, 114, 114, 115, 115, 115, 115, 116, 116, 116, 116, 117, 117, 117, 117, 118, 118, 118, 118, 119, 119, 119, 119, 120, 120, 120, 120, 121, 121, 121, 121, 122, 122, 122, 122, 123, 123, 123, 123, 124, 124, 124, 124, 125, 125, 125, 125, 126, 126, 126, 126, 127, 127, 127, 127, 128, 128, 128, 128, 129, 129, 129, 129, 130, 130, 130, 130, 131, 131, 131, 131, 132, 132, 132, 132, 133, 133, 133, 133, 134, 134, 134, 134, 135, 135, 135, 135, 136, 136, 136, 136, 137, 137, 137, 137, 138, 138, 138, 138, 139, 139, 139, 139, 140, 140, 140, 140, 141, 141, 141, 141, 142, 142, 142, 142, 143, 143, 143, 143, 144, 144, 144, 144, 145, 145, 145, 145, 146, 146, 146, 146, 147, 147, 147, 147, 148, 148, 148, 148, 149, 149, 149, 149, 150, 150, 150, 150, 151, 151, 151, 151, 152, 152, 152, 152, 153, 153, 153, 153, 154, 154, 154, 154, 155, 155, 155, 155, 156, 156, 156, 156, 157, 157, 157, 157, 158, 158, 158, 158, 159, 159, 159, 159, 160, 160, 160, 160, 161, 161, 161, 161, 162, 162, 162, 162, 163, 163, 163, 163, 164, 164, 164, 164, 165, 165, 165, 165, 166, 166, 166, 166, 167, 167, 167, 167, 168, 168, 168, 168, 169, 169, 169, 169, 170, 170, 170, 170, 171, 171, 171, 171, 172, 172, 172, 172, 173, 173, 173, 173, 174, 174, 174, 174, 175, 175, 175, 175, 176, 176, 176, 176, 177, 177, 177, 177, 178, 178, 178, 178, 179, 179, 179, 179, 180, 180, 180, 180, 181, 181, 181, 181, 182, 182, 182, 182, 183, 183, 183, 183, 184, 184, 184, 184, 185, 185, 185, 185, 186, 186, 186, 186, 187, 187, 187, 187, 188, 188, 188, 188, 189, 189, 189, 189, 190, 190, 190, 190, 191, 191, 191, 191, 192, 192, 192, 192, 193, 193, 193, 193, 194, 194, 194, 194, 195, 195, 195, 195, 196, 196, 196, 196, 197, 197, 197, 197, 198, 198, 198, 198, 199, 199, 199, 199, 200, 200, 200, 200, 201, 201, 201, 201, 202, 202, 202, 202, 203, 203, 203, 203, 204, 204, 204, 204, 205, 205, 205, 205, 206, 206, 206, 206, 207, 207, 207, 207, 208, 208, 208, 208, 209, 209, 209, 209, 210, 210, 210, 210, 211, 211, 211, 211, 212, 212, 212, 212, 213, 213, 213, 213, 214, 214, 214, 214, 215, 215, 215, 215, 216, 216, 216, 216, 217, 217, 217, 217, 218, 218, 218, 218, 219, 219, 219, 219, 220, 220, 220, 220, 221, 221, 221, 221, 222, 222, 222, 222, 223, 223, 223, 223, 224, 224, 224, 224, 225, 225, 225, 225, 226, 226, 226, 226, 227, 227, 227, 227, 228, 228, 228, 228, 229, 229, 229, 229, 230, 230, 230, 230, 231, 231, 231, 231, 232, 232, 232, 232, 233, 233, 233, 233, 234, 234, 234, 234, 235, 235, 235, 235, 236, 236, 236, 236, 237, 237, 237, 237, 238, 238, 238, 238, 239, 239, 239, 239, 240, 240, 240, 240, 241, 241, 241, 241, 242, 242, 242, 242, 243, 243, 243, 243, 244, 244, 244, 244, 245, 245, 245, 245, 246, 246, 246, 246, 247, 247, 247, 247, 248, 248, 248, 248, 249, 249, 249, 249, 250, 250, 250, 250, 251, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254, 254, 254, 254, 255, 255, 255, 255, 256, 256, 256, 256, 257, 257, 257, 257, 258, 258, 258, 258, 259, 259, 259, 259, 260, 260, 260, 260, 261, 261, 261, 261, 262, 262, 262, 262, 263, 263, 263, 263, 264, 264, 264, 264, 265, 265, 265, 265, 266, 266, 266, 266, 267, 267, 267, 267, 268, 268, 268, 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, 272, 272, 273, 273, 273, 273, 274, 274, 274, 274, 275, 275, 275, 275, 276, 276, 276, 276, 277, 277, 277, 277, 278, 278, 278, 278, 279, 279, 279, 279, 280, 280, 280, 280, 281, 281, 281, 281, 282, 282, 282, 282, 283, 283, 283, 283, 284, 284, 284, 284, 285, 285, 285, 285, 286, 286, 286, 286, 287, 287, 287, 287, 288, 288, 288, 288, 289, 289, 289, 289, 290, 290, 290, 290, 291, 291, 291, 291, 292, 292, 292, 292, 293, 293, 293, 293, 294, 294, 294, 294, 295, 295, 295, 295, 296, 296, 296, 296, 297, 297, 297, 297, 298, 298, 298, 298, 299, 299, 299, 299, 300, 300, 300, 300, 301, 301, 301, 301, 302, 302, 302, 302, 303, 303, 303, 303, 304, 304, 304, 304, 305, 305, 305, 305, 306, 306, 306, 306, 307, 307, 307, 307, 308, 308, 308, 308, 309, 309, 309, 309, 310, 310, 310, 310, 311, 311, 311, 311, 312, 312, 312, 312, 313, 313, 313, 313, 314, 314, 314, 314, 315, 315, 315, 315, 316, 316, 316, 316, 317, 317, 317, 317, 318, 318, 318, 318, 319, 319, 319, 319, 320, 320, 320, 320, 321, 321, 321, 321, 322, 322, 322, 322, 323, 323, 323, 323, 324, 324, 324, 324, 325, 325, 325, 325, 326, 326, 326, 326, 327, 327, 327, 327, 328, 328, 328, 328, 329, 329, 329, 329, 330, 330, 330, 330, 331, 331, 331, 331, 332, 332, 332, 332, 333, 333, 333, 333, 334, 334, 334, 334, 335, 335, 335, 335, 336, 336, 336, 336, 337, 337, 337, 337, 338, 338, 338, 338, 339, 339, 339, 339, 340, 340, 340, 340, 341, 341, 341, 341, 342, 342, 342, 342, 343, 343, 343, 343, 344, 344, 344, 344, 345, 345, 345, 345, 346, 346, 346, 346, 347, 347, 347, 347, 348, 348, 348, 348, 349, 349, 349, 349, 350, 350, 350, 350, 351, 351, 351, 351, 352, 352, 352, 352, 353, 353, 353, 353, 354, 354, 354, 354, 355, 355, 355, 355, 356, 356, 356, 356, 357, 357, 357, 357, 358, 358, 358, 358, 359, 359, 359, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479] ( + interpolation = "faceVarying" + ) + int primvars:ptexFaceOffset = 0 ( + interpolation = "constant" + ) + float[] primvars:u_map1 = [0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0, 0.05, 0.05, 0, 0.05, 0.1, 0.1, 0.05, 0.1, 0.15, 0.15, 0.1, 0.15, 0.2, 0.2, 0.15, 0.2, 0.25, 0.25, 0.2, 0.25, 0.3, 0.3, 0.25, 0.3, 0.35000002, 0.35000002, 0.3, 0.35000002, 0.40000004, 0.40000004, 0.35000002, 0.40000004, 0.45000005, 0.45000005, 0.40000004, 0.45000005, 0.50000006, 0.50000006, 0.45000005, 0.50000006, 0.5500001, 0.5500001, 0.50000006, 0.5500001, 0.6000001, 0.6000001, 0.5500001, 0.6000001, 0.6500001, 0.6500001, 0.6000001, 0.6500001, 0.7000001, 0.7000001, 0.6500001, 0.7000001, 0.7500001, 0.7500001, 0.7000001, 0.7500001, 0.80000013, 0.80000013, 0.7500001, 0.80000013, 0.85000014, 0.85000014, 0.80000013, 0.85000014, 0.90000015, 0.90000015, 0.85000014, 0.90000015, 0.95000017, 0.95000017, 0.90000015, 0.95000017, 1.0000001, 1.0000001, 0.95000017, 0.05, 0, 0.025, 0.1, 0.05, 0.075, 0.15, 0.1, 0.125, 0.2, 0.15, 0.175, 0.25, 0.2, 0.22500001, 0.3, 0.25, 0.275, 0.35000002, 0.3, 0.32500002, 0.40000004, 0.35000002, 0.375, 0.45000005, 0.40000004, 0.425, 0.50000006, 0.45000005, 0.475, 0.5500001, 0.50000006, 0.52500004, 0.6000001, 0.5500001, 0.575, 0.6500001, 0.6000001, 0.625, 0.7000001, 0.6500001, 0.675, 0.7500001, 0.7000001, 0.725, 0.80000013, 0.7500001, 0.77500004, 0.85000014, 0.80000013, 0.825, 0.90000015, 0.85000014, 0.875, 0.95000017, 0.90000015, 0.925, 1.0000001, 0.95000017, 0.975, 0, 0.05, 0.025, 0.05, 0.1, 0.075, 0.1, 0.15, 0.125, 0.15, 0.2, 0.175, 0.2, 0.25, 0.22500001, 0.25, 0.3, 0.275, 0.3, 0.35000002, 0.32500002, 0.35000002, 0.40000004, 0.375, 0.40000004, 0.45000005, 0.425, 0.45000005, 0.50000006, 0.475, 0.50000006, 0.5500001, 0.52500004, 0.5500001, 0.6000001, 0.575, 0.6000001, 0.6500001, 0.625, 0.6500001, 0.7000001, 0.675, 0.7000001, 0.7500001, 0.725, 0.7500001, 0.80000013, 0.77500004, 0.80000013, 0.85000014, 0.825, 0.85000014, 0.90000015, 0.875, 0.90000015, 0.95000017, 0.925, 0.95000017, 1.0000001, 0.975] ( + interpolation = "faceVarying" + ) + float[] primvars:v_map1 = [0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.35000002, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.40000004, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.45000005, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.50000006, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.5500001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6000001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.6500001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7000001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.7500001, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.80000013, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.85000014, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.90000015, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0.95000017, 0, 1] ( + interpolation = "vertex" + ) + } + + def Mesh "pCube1" ( + hidden = true + ) + { + float3[] extent = [(-0.5, -0.5, -0.5), (0.5, 0.5, 0.5)] + int[] faceVertexCounts = [4, 4, 4, 4, 4, 4] + int[] faceVertexIndices = [0, 1, 3, 2, 2, 3, 5, 4, 4, 5, 7, 6, 6, 7, 1, 0, 1, 7, 5, 3, 6, 0, 2, 4] + token interpolateBoundary = "edgeAndCorner" + uniform token orientation = "rightHanded" + float3[] points = [(-0.5, -0.5, 0.5), (0.5, -0.5, 0.5), (-0.5, 0.5, 0.5), (0.5, 0.5, 0.5), (-0.5, 0.5, -0.5), (0.5, 0.5, -0.5), (-0.5, -0.5, -0.5), (0.5, -0.5, -0.5)] + string primvars:__handleid = "${user:ModelInstance}_pCube1" ( + interpolation = "constant" + ) + color3f[] primvars:displayColor = [(0.217638, 0.217638, 0.217638)] + float3[] primvars:ModelBuildRefPose = [(-0.5, -0.5, 0.5), (0.5, -0.5, 0.5), (-0.5, 0.5, 0.5), (0.5, 0.5, 0.5), (-0.5, 0.5, -0.5), (0.5, 0.5, -0.5), (-0.5, -0.5, -0.5), (0.5, -0.5, -0.5)] ( + interpolation = "vertex" + ) + float[] primvars:ptexFaceIndex = [0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5] ( + interpolation = "faceVarying" + ) + int primvars:ptexFaceOffset = 480 ( + interpolation = "constant" + ) + float[] primvars:u_map1 = [0.375, 0.625, 0.625, 0.375, 0.375, 0.625, 0.625, 0.375, 0.375, 0.625, 0.625, 0.375, 0.375, 0.625, 0.625, 0.375, 0.625, 0.875, 0.875, 0.625, 0.125, 0.375, 0.375, 0.125] ( + interpolation = "faceVarying" + ) + float[] primvars:v_map1 = [0, 0, 0.25, 0.25, 0.25, 0.25, 0.5, 0.5, 0.5, 0.5, 0.75, 0.75, 0.75, 0.75, 1, 1, 0, 0, 0.25, 0.25, 0, 0, 0.25, 0.25] ( + interpolation = "faceVarying" + ) + } + + def Mesh "pCylinder1" ( + hidden = true + ) + { + float3[] extent = [(-1, -1, -1), (1, 1, 1)] + int[] faceVertexCounts = [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3] + int[] faceVertexIndices = [0, 1, 21, 20, 1, 2, 22, 21, 2, 3, 23, 22, 3, 4, 24, 23, 4, 5, 25, 24, 5, 6, 26, 25, 6, 7, 27, 26, 7, 8, 28, 27, 8, 9, 29, 28, 9, 10, 30, 29, 10, 11, 31, 30, 11, 12, 32, 31, 12, 13, 33, 32, 13, 14, 34, 33, 14, 15, 35, 34, 15, 16, 36, 35, 16, 17, 37, 36, 17, 18, 38, 37, 18, 19, 39, 38, 19, 0, 20, 39, 1, 0, 40, 2, 1, 40, 3, 2, 40, 4, 3, 40, 5, 4, 40, 6, 5, 40, 7, 6, 40, 8, 7, 40, 9, 8, 40, 10, 9, 40, 11, 10, 40, 12, 11, 40, 13, 12, 40, 14, 13, 40, 15, 14, 40, 16, 15, 40, 17, 16, 40, 18, 17, 40, 19, 18, 40, 0, 19, 40, 20, 21, 41, 21, 22, 41, 22, 23, 41, 23, 24, 41, 24, 25, 41, 25, 26, 41, 26, 27, 41, 27, 28, 41, 28, 29, 41, 29, 30, 41, 30, 31, 41, 31, 32, 41, 32, 33, 41, 33, 34, 41, 34, 35, 41, 35, 36, 41, 36, 37, 41, 37, 38, 41, 38, 39, 41, 39, 20, 41] + token interpolateBoundary = "edgeAndCorner" + uniform token orientation = "rightHanded" + float3[] points = [(0.951057, -1, -0.309017), (0.809018, -1, -0.587786), (0.587786, -1, -0.809017), (0.309017, -1, -0.951057), (0, -1, -1), (-0.309017, -1, -0.951057), (-0.587785, -1, -0.809017), (-0.809017, -1, -0.587785), (-0.951057, -1, -0.309017), (-1, -1, 0), (-0.951057, -1, 0.309017), (-0.809017, -1, 0.587785), (-0.587785, -1, 0.809017), (-0.309017, -1, 0.951057), (-2.98023e-08, -1, 1), (0.309017, -1, 0.951057), (0.587785, -1, 0.809017), (0.809017, -1, 0.587785), (0.951057, -1, 0.309017), (1, -1, 0), (0.951057, 1, -0.309017), (0.809018, 1, -0.587786), (0.587786, 1, -0.809017), (0.309017, 1, -0.951057), (0, 1, -1), (-0.309017, 1, -0.951057), (-0.587785, 1, -0.809017), (-0.809017, 1, -0.587785), (-0.951057, 1, -0.309017), (-1, 1, 0), (-0.951057, 1, 0.309017), (-0.809017, 1, 0.587785), (-0.587785, 1, 0.809017), (-0.309017, 1, 0.951057), (-2.98023e-08, 1, 1), (0.309017, 1, 0.951057), (0.587785, 1, 0.809017), (0.809017, 1, 0.587785), (0.951057, 1, 0.309017), (1, 1, 0), (0, -1, 0), (0, 1, 0)] + string primvars:__handleid = "${user:ModelInstance}_pCylinder1" ( + interpolation = "constant" + ) + color3f[] primvars:displayColor = [(0.217638, 0.217638, 0.217638)] + float3[] primvars:ModelBuildRefPose = [(0.951057, -1, -0.309017), (0.809018, -1, -0.587786), (0.587786, -1, -0.809017), (0.309017, -1, -0.951057), (0, -1, -1), (-0.309017, -1, -0.951057), (-0.587785, -1, -0.809017), (-0.809017, -1, -0.587785), (-0.951057, -1, -0.309017), (-1, -1, 0), (-0.951057, -1, 0.309017), (-0.809017, -1, 0.587785), (-0.587785, -1, 0.809017), (-0.309017, -1, 0.951057), (-2.98023e-08, -1, 1), (0.309017, -1, 0.951057), (0.587785, -1, 0.809017), (0.809017, -1, 0.587785), (0.951057, -1, 0.309017), (1, -1, 0), (0.951057, 1, -0.309017), (0.809018, 1, -0.587786), (0.587786, 1, -0.809017), (0.309017, 1, -0.951057), (0, 1, -1), (-0.309017, 1, -0.951057), (-0.587785, 1, -0.809017), (-0.809017, 1, -0.587785), (-0.951057, 1, -0.309017), (-1, 1, 0), (-0.951057, 1, 0.309017), (-0.809017, 1, 0.587785), (-0.587785, 1, 0.809017), (-0.309017, 1, 0.951057), (-2.98023e-08, 1, 1), (0.309017, 1, 0.951057), (0.587785, 1, 0.809017), (0.809017, 1, 0.587785), (0.951057, 1, 0.309017), (1, 1, 0), (0, -1, 0), (0, 1, 0)] ( + interpolation = "vertex" + ) + float[] primvars:ptexFaceIndex = [0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139] ( + interpolation = "faceVarying" + ) + int primvars:ptexFaceOffset = 486 ( + interpolation = "constant" + ) + float[] primvars:u_map1 = [0.375, 0.3875, 0.3875, 0.375, 0.3875, 0.39999998, 0.39999998, 0.3875, 0.39999998, 0.41249996, 0.41249996, 0.39999998, 0.41249996, 0.42499995, 0.42499995, 0.41249996, 0.42499995, 0.43749994, 0.43749994, 0.42499995, 0.43749994, 0.44999993, 0.44999993, 0.43749994, 0.44999993, 0.46249992, 0.46249992, 0.44999993, 0.46249992, 0.4749999, 0.4749999, 0.46249992, 0.4749999, 0.4874999, 0.4874999, 0.4749999, 0.4874999, 0.49999988, 0.49999988, 0.4874999, 0.49999988, 0.51249987, 0.51249987, 0.49999988, 0.51249987, 0.52499986, 0.52499986, 0.51249987, 0.52499986, 0.53749985, 0.53749985, 0.52499986, 0.53749985, 0.54999983, 0.54999983, 0.53749985, 0.54999983, 0.5624998, 0.5624998, 0.54999983, 0.5624998, 0.5749998, 0.5749998, 0.5624998, 0.5749998, 0.5874998, 0.5874998, 0.5749998, 0.5874998, 0.5999998, 0.5999998, 0.5874998, 0.5999998, 0.6124998, 0.6124998, 0.5999998, 0.6124998, 0.62499976, 0.62499976, 0.6124998, 0.626409, 0.64860266, 0.5, 0.5918415, 0.626409, 0.5, 0.54828393, 0.5918415, 0.5, 0.5, 0.54828393, 0.5, 0.45171607, 0.5, 0.5, 0.4081585, 0.45171607, 0.5, 0.37359107, 0.4081585, 0.5, 0.3513974, 0.37359107, 0.5, 0.34374997, 0.3513974, 0.5, 0.3513974, 0.34374997, 0.5, 0.37359107, 0.3513974, 0.5, 0.40815854, 0.37359107, 0.5, 0.4517161, 0.40815854, 0.5, 0.5, 0.4517161, 0.5, 0.5482839, 0.5, 0.5, 0.59184146, 0.5482839, 0.5, 0.62640893, 0.59184146, 0.5, 0.6486026, 0.62640893, 0.5, 0.65625, 0.6486026, 0.5, 0.64860266, 0.65625, 0.5, 0.6486026, 0.62640893, 0.5, 0.62640893, 0.59184146, 0.5, 0.59184146, 0.5482839, 0.5, 0.5482839, 0.5, 0.5, 0.5, 0.4517161, 0.5, 0.4517161, 0.40815854, 0.5, 0.40815854, 0.37359107, 0.5, 0.37359107, 0.3513974, 0.5, 0.3513974, 0.34374997, 0.5, 0.34374997, 0.3513974, 0.5, 0.3513974, 0.37359107, 0.5, 0.37359107, 0.4081585, 0.5, 0.4081585, 0.45171607, 0.5, 0.45171607, 0.5, 0.5, 0.5, 0.54828393, 0.5, 0.54828393, 0.5918415, 0.5, 0.5918415, 0.626409, 0.5, 0.626409, 0.64860266, 0.5, 0.64860266, 0.65625, 0.5, 0.65625, 0.6486026, 0.5] ( + interpolation = "faceVarying" + ) + float[] primvars:v_map1 = [0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.3125, 0.3125, 0.68843985, 0.68843985, 0.064408496, 0.107966065, 0.15, 0.02984102, 0.064408496, 0.15, 0.0076473355, 0.02984102, 0.15, -7.4505806e-8, 0.0076473355, 0.15, 0.0076473504, -7.4505806e-8, 0.15, 0.02984105, 0.0076473504, 0.15, 0.064408526, 0.02984105, 0.15, 0.10796608, 0.064408526, 0.15, 0.15625, 0.10796608, 0.15, 0.20453392, 0.15625, 0.15, 0.24809146, 0.20453392, 0.15, 0.28265893, 0.24809146, 0.15, 0.3048526, 0.28265893, 0.15, 0.3125, 0.3048526, 0.15, 0.3048526, 0.3125, 0.15, 0.28265893, 0.3048526, 0.15, 0.24809146, 0.28265893, 0.15, 0.2045339, 0.24809146, 0.15, 0.15625, 0.2045339, 0.15, 0.107966065, 0.15625, 0.15, 0.89203393, 0.93559146, 0.8375, 0.93559146, 0.97015893, 0.8375, 0.97015893, 0.9923526, 0.8375, 0.9923526, 1, 0.8375, 1, 0.9923526, 0.8375, 0.9923526, 0.97015893, 0.8375, 0.97015893, 0.93559146, 0.8375, 0.93559146, 0.89203393, 0.8375, 0.89203393, 0.84375, 0.8375, 0.84375, 0.79546607, 0.8375, 0.79546607, 0.75190854, 0.8375, 0.75190854, 0.71734107, 0.8375, 0.71734107, 0.69514734, 0.8375, 0.69514734, 0.68749994, 0.8375, 0.68749994, 0.69514734, 0.8375, 0.69514734, 0.717341, 0.8375, 0.717341, 0.7519085, 0.8375, 0.7519085, 0.79546607, 0.8375, 0.79546607, 0.84375, 0.8375, 0.84375, 0.89203393, 0.8375] ( + interpolation = "faceVarying" + ) + } + + def Mesh "pCone1" ( + hidden = true + ) + { + float3[] extent = [(-1, -1, -1), (1, 1, 1)] + int[] faceVertexCounts = [20, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3] + int[] faceVertexIndices = [0, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 1, 20, 1, 2, 20, 2, 3, 20, 3, 4, 20, 4, 5, 20, 5, 6, 20, 6, 7, 20, 7, 8, 20, 8, 9, 20, 9, 10, 20, 10, 11, 20, 11, 12, 20, 12, 13, 20, 13, 14, 20, 14, 15, 20, 15, 16, 20, 16, 17, 20, 17, 18, 20, 18, 19, 20, 19, 0, 20] + token interpolateBoundary = "edgeAndCorner" + uniform token orientation = "rightHanded" + float3[] points = [(0.951057, -1, -0.309017), (0.809018, -1, -0.587786), (0.587786, -1, -0.809017), (0.309017, -1, -0.951057), (0, -1, -1), (-0.309017, -1, -0.951057), (-0.587785, -1, -0.809017), (-0.809017, -1, -0.587785), (-0.951057, -1, -0.309017), (-1, -1, 0), (-0.951057, -1, 0.309017), (-0.809017, -1, 0.587785), (-0.587785, -1, 0.809017), (-0.309017, -1, 0.951057), (-2.98023e-08, -1, 1), (0.309017, -1, 0.951057), (0.587785, -1, 0.809017), (0.809017, -1, 0.587785), (0.951057, -1, 0.309017), (1, -1, 0), (0, 1, 0)] + string primvars:__handleid = "${user:ModelInstance}_pCone1" ( + interpolation = "constant" + ) + color3f[] primvars:displayColor = [(0.217638, 0.217638, 0.217638)] + float3[] primvars:ModelBuildRefPose = [(0.951057, -1, -0.309017), (0.809018, -1, -0.587786), (0.587786, -1, -0.809017), (0.309017, -1, -0.951057), (0, -1, -1), (-0.309017, -1, -0.951057), (-0.587785, -1, -0.809017), (-0.809017, -1, -0.587785), (-0.951057, -1, -0.309017), (-1, -1, 0), (-0.951057, -1, 0.309017), (-0.809017, -1, 0.587785), (-0.587785, -1, 0.809017), (-0.309017, -1, 0.951057), (-2.98023e-08, -1, 1), (0.309017, -1, 0.951057), (0.587785, -1, 0.809017), (0.809017, -1, 0.587785), (0.951057, -1, 0.309017), (1, -1, 0), (0, 1, 0)] ( + interpolation = "vertex" + ) + float[] primvars:ptexFaceIndex = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79] ( + interpolation = "faceVarying" + ) + int primvars:ptexFaceOffset = 626 ( + interpolation = "constant" + ) + float[] primvars:u_map1 = [0.7377643, 0.75, 0.7377641, 0.70225424, 0.6469463, 0.57725424, 0.5, 0.42274573, 0.35305366, 0.2977457, 0.26223582, 0.24999994, 0.26223582, 0.2977457, 0.35305363, 0.4227457, 0.5, 0.5772543, 0.64694643, 0.7022544, 0.25, 0.275, 0.5, 0.275, 0.3, 0.5, 0.3, 0.32500002, 0.5, 0.32500002, 0.35000002, 0.5, 0.35000002, 0.37500003, 0.5, 0.37500003, 0.40000004, 0.5, 0.40000004, 0.42500004, 0.5, 0.42500004, 0.45000005, 0.5, 0.45000005, 0.47500005, 0.5, 0.47500005, 0.50000006, 0.5, 0.50000006, 0.52500004, 0.5, 0.52500004, 0.55, 0.5, 0.55, 0.575, 0.5, 0.575, 0.59999996, 0.5, 0.59999996, 0.62499994, 0.5, 0.62499994, 0.6499999, 0.5, 0.6499999, 0.6749999, 0.5, 0.6749999, 0.69999987, 0.5, 0.69999987, 0.72499985, 0.5, 0.72499985, 0.7499998, 0.5] ( + interpolation = "faceVarying" + ) + float[] primvars:v_map1 = [0.1727457, 0.25, 0.32725424, 0.3969463, 0.45225427, 0.48776415, 0.5, 0.48776418, 0.4522543, 0.39694634, 0.32725427, 0.25, 0.17274573, 0.103053644, 0.047745675, 0.012235761, -1.1920929e-7, 0.012235746, 0.04774563, 0.1030536, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1] ( + interpolation = "faceVarying" + ) + } + + def Mesh "pTorus1" ( + hidden = true + ) + { + float3[] extent = [(-1.5, -0.5, -1.5), (1.5, 0.5, 1.5)] + int[] faceVertexCounts = [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4] + int[] faceVertexIndices = [1, 0, 20, 21, 2, 1, 21, 22, 3, 2, 22, 23, 4, 3, 23, 24, 5, 4, 24, 25, 6, 5, 25, 26, 7, 6, 26, 27, 8, 7, 27, 28, 9, 8, 28, 29, 10, 9, 29, 30, 11, 10, 30, 31, 12, 11, 31, 32, 13, 12, 32, 33, 14, 13, 33, 34, 15, 14, 34, 35, 16, 15, 35, 36, 17, 16, 36, 37, 18, 17, 37, 38, 19, 18, 38, 39, 0, 19, 39, 20, 21, 20, 40, 41, 22, 21, 41, 42, 23, 22, 42, 43, 24, 23, 43, 44, 25, 24, 44, 45, 26, 25, 45, 46, 27, 26, 46, 47, 28, 27, 47, 48, 29, 28, 48, 49, 30, 29, 49, 50, 31, 30, 50, 51, 32, 31, 51, 52, 33, 32, 52, 53, 34, 33, 53, 54, 35, 34, 54, 55, 36, 35, 55, 56, 37, 36, 56, 57, 38, 37, 57, 58, 39, 38, 58, 59, 20, 39, 59, 40, 41, 40, 60, 61, 42, 41, 61, 62, 43, 42, 62, 63, 44, 43, 63, 64, 45, 44, 64, 65, 46, 45, 65, 66, 47, 46, 66, 67, 48, 47, 67, 68, 49, 48, 68, 69, 50, 49, 69, 70, 51, 50, 70, 71, 52, 51, 71, 72, 53, 52, 72, 73, 54, 53, 73, 74, 55, 54, 74, 75, 56, 55, 75, 76, 57, 56, 76, 77, 58, 57, 77, 78, 59, 58, 78, 79, 40, 59, 79, 60, 61, 60, 80, 81, 62, 61, 81, 82, 63, 62, 82, 83, 64, 63, 83, 84, 65, 64, 84, 85, 66, 65, 85, 86, 67, 66, 86, 87, 68, 67, 87, 88, 69, 68, 88, 89, 70, 69, 89, 90, 71, 70, 90, 91, 72, 71, 91, 92, 73, 72, 92, 93, 74, 73, 93, 94, 75, 74, 94, 95, 76, 75, 95, 96, 77, 76, 96, 97, 78, 77, 97, 98, 79, 78, 98, 99, 60, 79, 99, 80, 81, 80, 100, 101, 82, 81, 101, 102, 83, 82, 102, 103, 84, 83, 103, 104, 85, 84, 104, 105, 86, 85, 105, 106, 87, 86, 106, 107, 88, 87, 107, 108, 89, 88, 108, 109, 90, 89, 109, 110, 91, 90, 110, 111, 92, 91, 111, 112, 93, 92, 112, 113, 94, 93, 113, 114, 95, 94, 114, 115, 96, 95, 115, 116, 97, 96, 116, 117, 98, 97, 117, 118, 99, 98, 118, 119, 80, 99, 119, 100, 101, 100, 120, 121, 102, 101, 121, 122, 103, 102, 122, 123, 104, 103, 123, 124, 105, 104, 124, 125, 106, 105, 125, 126, 107, 106, 126, 127, 108, 107, 127, 128, 109, 108, 128, 129, 110, 109, 129, 130, 111, 110, 130, 131, 112, 111, 131, 132, 113, 112, 132, 133, 114, 113, 133, 134, 115, 114, 134, 135, 116, 115, 135, 136, 117, 116, 136, 137, 118, 117, 137, 138, 119, 118, 138, 139, 100, 119, 139, 120, 121, 120, 140, 141, 122, 121, 141, 142, 123, 122, 142, 143, 124, 123, 143, 144, 125, 124, 144, 145, 126, 125, 145, 146, 127, 126, 146, 147, 128, 127, 147, 148, 129, 128, 148, 149, 130, 129, 149, 150, 131, 130, 150, 151, 132, 131, 151, 152, 133, 132, 152, 153, 134, 133, 153, 154, 135, 134, 154, 155, 136, 135, 155, 156, 137, 136, 156, 157, 138, 137, 157, 158, 139, 138, 158, 159, 120, 139, 159, 140, 141, 140, 160, 161, 142, 141, 161, 162, 143, 142, 162, 163, 144, 143, 163, 164, 145, 144, 164, 165, 146, 145, 165, 166, 147, 146, 166, 167, 148, 147, 167, 168, 149, 148, 168, 169, 150, 149, 169, 170, 151, 150, 170, 171, 152, 151, 171, 172, 153, 152, 172, 173, 154, 153, 173, 174, 155, 154, 174, 175, 156, 155, 175, 176, 157, 156, 176, 177, 158, 157, 177, 178, 159, 158, 178, 179, 140, 159, 179, 160, 161, 160, 180, 181, 162, 161, 181, 182, 163, 162, 182, 183, 164, 163, 183, 184, 165, 164, 184, 185, 166, 165, 185, 186, 167, 166, 186, 187, 168, 167, 187, 188, 169, 168, 188, 189, 170, 169, 189, 190, 171, 170, 190, 191, 172, 171, 191, 192, 173, 172, 192, 193, 174, 173, 193, 194, 175, 174, 194, 195, 176, 175, 195, 196, 177, 176, 196, 197, 178, 177, 197, 198, 179, 178, 198, 199, 160, 179, 199, 180, 181, 180, 200, 201, 182, 181, 201, 202, 183, 182, 202, 203, 184, 183, 203, 204, 185, 184, 204, 205, 186, 185, 205, 206, 187, 186, 206, 207, 188, 187, 207, 208, 189, 188, 208, 209, 190, 189, 209, 210, 191, 190, 210, 211, 192, 191, 211, 212, 193, 192, 212, 213, 194, 193, 213, 214, 195, 194, 214, 215, 196, 195, 215, 216, 197, 196, 216, 217, 198, 197, 217, 218, 199, 198, 218, 219, 180, 199, 219, 200, 201, 200, 220, 221, 202, 201, 221, 222, 203, 202, 222, 223, 204, 203, 223, 224, 205, 204, 224, 225, 206, 205, 225, 226, 207, 206, 226, 227, 208, 207, 227, 228, 209, 208, 228, 229, 210, 209, 229, 230, 211, 210, 230, 231, 212, 211, 231, 232, 213, 212, 232, 233, 214, 213, 233, 234, 215, 214, 234, 235, 216, 215, 235, 236, 217, 216, 236, 237, 218, 217, 237, 238, 219, 218, 238, 239, 200, 219, 239, 220, 221, 220, 240, 241, 222, 221, 241, 242, 223, 222, 242, 243, 224, 223, 243, 244, 225, 224, 244, 245, 226, 225, 245, 246, 227, 226, 246, 247, 228, 227, 247, 248, 229, 228, 248, 249, 230, 229, 249, 250, 231, 230, 250, 251, 232, 231, 251, 252, 233, 232, 252, 253, 234, 233, 253, 254, 235, 234, 254, 255, 236, 235, 255, 256, 237, 236, 256, 257, 238, 237, 257, 258, 239, 238, 258, 259, 220, 239, 259, 240, 241, 240, 260, 261, 242, 241, 261, 262, 243, 242, 262, 263, 244, 243, 263, 264, 245, 244, 264, 265, 246, 245, 265, 266, 247, 246, 266, 267, 248, 247, 267, 268, 249, 248, 268, 269, 250, 249, 269, 270, 251, 250, 270, 271, 252, 251, 271, 272, 253, 252, 272, 273, 254, 253, 273, 274, 255, 254, 274, 275, 256, 255, 275, 276, 257, 256, 276, 277, 258, 257, 277, 278, 259, 258, 278, 279, 240, 259, 279, 260, 261, 260, 280, 281, 262, 261, 281, 282, 263, 262, 282, 283, 264, 263, 283, 284, 265, 264, 284, 285, 266, 265, 285, 286, 267, 266, 286, 287, 268, 267, 287, 288, 269, 268, 288, 289, 270, 269, 289, 290, 271, 270, 290, 291, 272, 271, 291, 292, 273, 272, 292, 293, 274, 273, 293, 294, 275, 274, 294, 295, 276, 275, 295, 296, 277, 276, 296, 297, 278, 277, 297, 298, 279, 278, 298, 299, 260, 279, 299, 280, 281, 280, 300, 301, 282, 281, 301, 302, 283, 282, 302, 303, 284, 283, 303, 304, 285, 284, 304, 305, 286, 285, 305, 306, 287, 286, 306, 307, 288, 287, 307, 308, 289, 288, 308, 309, 290, 289, 309, 310, 291, 290, 310, 311, 292, 291, 311, 312, 293, 292, 312, 313, 294, 293, 313, 314, 295, 294, 314, 315, 296, 295, 315, 316, 297, 296, 316, 317, 298, 297, 317, 318, 299, 298, 318, 319, 280, 299, 319, 300, 301, 300, 320, 321, 302, 301, 321, 322, 303, 302, 322, 323, 304, 303, 323, 324, 305, 304, 324, 325, 306, 305, 325, 326, 307, 306, 326, 327, 308, 307, 327, 328, 309, 308, 328, 329, 310, 309, 329, 330, 311, 310, 330, 331, 312, 311, 331, 332, 313, 312, 332, 333, 314, 313, 333, 334, 315, 314, 334, 335, 316, 315, 335, 336, 317, 316, 336, 337, 318, 317, 337, 338, 319, 318, 338, 339, 300, 319, 339, 320, 321, 320, 340, 341, 322, 321, 341, 342, 323, 322, 342, 343, 324, 323, 343, 344, 325, 324, 344, 345, 326, 325, 345, 346, 327, 326, 346, 347, 328, 327, 347, 348, 329, 328, 348, 349, 330, 329, 349, 350, 331, 330, 350, 351, 332, 331, 351, 352, 333, 332, 352, 353, 334, 333, 353, 354, 335, 334, 354, 355, 336, 335, 355, 356, 337, 336, 356, 357, 338, 337, 357, 358, 339, 338, 358, 359, 320, 339, 359, 340, 341, 340, 360, 361, 342, 341, 361, 362, 343, 342, 362, 363, 344, 343, 363, 364, 345, 344, 364, 365, 346, 345, 365, 366, 347, 346, 366, 367, 348, 347, 367, 368, 349, 348, 368, 369, 350, 349, 369, 370, 351, 350, 370, 371, 352, 351, 371, 372, 353, 352, 372, 373, 354, 353, 373, 374, 355, 354, 374, 375, 356, 355, 375, 376, 357, 356, 376, 377, 358, 357, 377, 378, 359, 358, 378, 379, 340, 359, 379, 360, 361, 360, 380, 381, 362, 361, 381, 382, 363, 362, 382, 383, 364, 363, 383, 384, 365, 364, 384, 385, 366, 365, 385, 386, 367, 366, 386, 387, 368, 367, 387, 388, 369, 368, 388, 389, 370, 369, 389, 390, 371, 370, 390, 391, 372, 371, 391, 392, 373, 372, 392, 393, 374, 373, 393, 394, 375, 374, 394, 395, 376, 375, 395, 396, 377, 376, 396, 397, 378, 377, 397, 398, 379, 378, 398, 399, 360, 379, 399, 380, 381, 380, 0, 1, 382, 381, 1, 2, 383, 382, 2, 3, 384, 383, 3, 4, 385, 384, 4, 5, 386, 385, 5, 6, 387, 386, 6, 7, 388, 387, 7, 8, 389, 388, 8, 9, 390, 389, 9, 10, 391, 390, 10, 11, 392, 391, 11, 12, 393, 392, 12, 13, 394, 393, 13, 14, 395, 394, 14, 15, 396, 395, 15, 16, 397, 396, 16, 17, 398, 397, 17, 18, 399, 398, 18, 19, 380, 399, 19, 0] + token interpolateBoundary = "edgeAndCorner" + uniform token orientation = "rightHanded" + float3[] points = [(0.475529, 0, -0.154509), (0.404509, 0, -0.293893), (0.293893, 0, -0.404509), (0.154509, 0, -0.475529), (0, 0, -0.5), (-0.154509, 0, -0.475528), (-0.293893, 0, -0.404509), (-0.404509, 0, -0.293893), (-0.475528, 0, -0.154509), (-0.5, 0, 0), (-0.475528, 0, 0.154509), (-0.404509, 0, 0.293893), (-0.293893, 0, 0.404509), (-0.154509, 0, 0.475528), (-1.49012e-08, 0, 0.5), (0.154508, 0, 0.475528), (0.293893, 0, 0.404509), (0.404509, 0, 0.293893), (0.475528, 0, 0.154509), (0.5, 0, 0), (0.498803, 0.154509, -0.162071), (0.424307, 0.154509, -0.308277), (0.308277, 0.154509, -0.424307), (0.162071, 0.154509, -0.498803), (0, 0.154509, -0.524472), (-0.162071, 0.154509, -0.498803), (-0.308277, 0.154509, -0.424307), (-0.424307, 0.154509, -0.308277), (-0.498802, 0.154509, -0.162071), (-0.524472, 0.154509, 0), (-0.498802, 0.154509, 0.162071), (-0.424307, 0.154509, 0.308277), (-0.308277, 0.154509, 0.424307), (-0.162071, 0.154509, 0.498802), (-1.56305e-08, 0.154509, 0.524472), (0.162071, 0.154509, 0.498802), (0.308277, 0.154509, 0.424307), (0.424307, 0.154509, 0.308277), (0.498802, 0.154509, 0.162071), (0.524472, 0.154509, 0), (0.566346, 0.293893, -0.184017), (0.481763, 0.293893, -0.350021), (0.350021, 0.293893, -0.481763), (0.184017, 0.293893, -0.566346), (0, 0.293893, -0.595492), (-0.184017, 0.293893, -0.566346), (-0.350021, 0.293893, -0.481763), (-0.481763, 0.293893, -0.350021), (-0.566346, 0.293893, -0.184017), (-0.595492, 0.293893, 0), (-0.566346, 0.293893, 0.184017), (-0.481763, 0.293893, 0.350021), (-0.350021, 0.293893, 0.481763), (-0.184017, 0.293893, 0.566346), (-1.7747e-08, 0.293893, 0.595492), (0.184017, 0.293893, 0.566346), (0.350021, 0.293893, 0.481763), (0.481763, 0.293893, 0.350021), (0.566346, 0.293893, 0.184017), (0.595492, 0.293893, 0), (0.671548, 0.404509, -0.218199), (0.571253, 0.404509, -0.41504), (0.41504, 0.404509, -0.571253), (0.218199, 0.404509, -0.671548), (0, 0.404509, -0.706108), (-0.218199, 0.404509, -0.671548), (-0.41504, 0.404509, -0.571253), (-0.571253, 0.404509, -0.41504), (-0.671548, 0.404509, -0.218199), (-0.706108, 0.404509, 0), (-0.671548, 0.404509, 0.218199), (-0.571253, 0.404509, 0.41504), (-0.41504, 0.404509, 0.571253), (-0.218199, 0.404509, 0.671548), (-2.10436e-08, 0.404509, 0.706107), (0.218199, 0.404509, 0.671548), (0.41504, 0.404509, 0.571253), (0.571253, 0.404509, 0.41504), (0.671548, 0.404509, 0.218199), (0.706107, 0.404509, 0), (0.804111, 0.475528, -0.261271), (0.684017, 0.475528, -0.496968), (0.496968, 0.475528, -0.684017), (0.261271, 0.475528, -0.804111), (0, 0.475528, -0.845492), (-0.261271, 0.475528, -0.804111), (-0.496968, 0.475528, -0.684017), (-0.684017, 0.475528, -0.496968), (-0.80411, 0.475528, -0.261271), (-0.845492, 0.475528, 0), (-0.80411, 0.475528, 0.261271), (-0.684017, 0.475528, 0.496968), (-0.496968, 0.475528, 0.684017), (-0.261271, 0.475528, 0.80411), (-2.51976e-08, 0.475528, 0.845492), (0.261271, 0.475528, 0.80411), (0.496967, 0.475528, 0.684017), (0.684017, 0.475528, 0.496967), (0.80411, 0.475528, 0.261271), (0.845492, 0.475528, 0), (0.951057, 0.5, -0.309017), (0.809018, 0.5, -0.587786), (0.587786, 0.5, -0.809017), (0.309017, 0.5, -0.951057), (0, 0.5, -1), (-0.309017, 0.5, -0.951057), (-0.587785, 0.5, -0.809017), (-0.809017, 0.5, -0.587785), (-0.951057, 0.5, -0.309017), (-1, 0.5, 0), (-0.951057, 0.5, 0.309017), (-0.809017, 0.5, 0.587785), (-0.587785, 0.5, 0.809017), (-0.309017, 0.5, 0.951057), (-2.98023e-08, 0.5, 1), (0.309017, 0.5, 0.951057), (0.587785, 0.5, 0.809017), (0.809017, 0.5, 0.587785), (0.951057, 0.5, 0.309017), (1, 0.5, 0), (1.098, 0.475528, -0.356763), (0.934018, 0.475528, -0.678604), (0.678604, 0.475528, -0.934018), (0.356763, 0.475528, -1.098), (0, 0.475528, -1.15451), (-0.356763, 0.475528, -1.098), (-0.678603, 0.475528, -0.934017), (-0.934017, 0.475528, -0.678603), (-1.098, 0.475528, -0.356763), (-1.15451, 0.475528, 0), (-1.098, 0.475528, 0.356763), (-0.934017, 0.475528, 0.678603), (-0.678603, 0.475528, 0.934017), (-0.356763, 0.475528, 1.098), (-3.4407e-08, 0.475528, 1.15451), (0.356763, 0.475528, 1.098), (0.678603, 0.475528, 0.934017), (0.934017, 0.475528, 0.678603), (1.098, 0.475528, 0.356763), (1.15451, 0.475528, 0), (1.23057, 0.404509, -0.399835), (1.04678, 0.404509, -0.760531), (0.760531, 0.404509, -1.04678), (0.399835, 0.404509, -1.23057), (0, 0.404509, -1.29389), (-0.399835, 0.404509, -1.23057), (-0.760531, 0.404509, -1.04678), (-1.04678, 0.404509, -0.760531), (-1.23057, 0.404509, -0.399835), (-1.29389, 0.404509, 0), (-1.23057, 0.404509, 0.399835), (-1.04678, 0.404509, 0.760531), (-0.760531, 0.404509, 1.04678), (-0.399835, 0.404509, 1.23057), (-3.8561e-08, 0.404509, 1.29389), (0.399835, 0.404509, 1.23057), (0.760531, 0.404509, 1.04678), (1.04678, 0.404509, 0.760531), (1.23057, 0.404509, 0.399835), (1.29389, 0.404509, 0), (1.33577, 0.293893, -0.434017), (1.13627, 0.293893, -0.82555), (0.82555, 0.293893, -1.13627), (0.434017, 0.293893, -1.33577), (0, 0.293893, -1.40451), (-0.434017, 0.293893, -1.33577), (-0.82555, 0.293893, -1.13627), (-1.13627, 0.293893, -0.82555), (-1.33577, 0.293893, -0.434017), (-1.40451, 0.293893, 0), (-1.33577, 0.293893, 0.434017), (-1.13627, 0.293893, 0.82555), (-0.82555, 0.293893, 1.13627), (-0.434017, 0.293893, 1.33577), (-4.18576e-08, 0.293893, 1.40451), (0.434017, 0.293893, 1.33577), (0.825549, 0.293893, 1.13627), (1.13627, 0.293893, 0.825549), (1.33577, 0.293893, 0.434017), (1.40451, 0.293893, 0), (1.40331, 0.154509, -0.455964), (1.19373, 0.154509, -0.867294), (0.867294, 0.154509, -1.19373), (0.455964, 0.154509, -1.40331), (0, 0.154509, -1.47553), (-0.455964, 0.154509, -1.40331), (-0.867294, 0.154509, -1.19373), (-1.19373, 0.154509, -0.867294), (-1.40331, 0.154509, -0.455963), (-1.47553, 0.154509, 0), (-1.40331, 0.154509, 0.455963), (-1.19373, 0.154509, 0.867294), (-0.867294, 0.154509, 1.19373), (-0.455963, 0.154509, 1.40331), (-4.39742e-08, 0.154509, 1.47553), (0.455963, 0.154509, 1.40331), (0.867294, 0.154509, 1.19373), (1.19373, 0.154509, 0.867294), (1.40331, 0.154509, 0.455963), (1.47553, 0.154509, 0), (1.42659, 0, -0.463526), (1.21353, 0, -0.881678), (0.881678, 0, -1.21353), (0.463526, 0, -1.42659), (0, 0, -1.5), (-0.463526, 0, -1.42659), (-0.881678, 0, -1.21353), (-1.21353, 0, -0.881678), (-1.42659, 0, -0.463526), (-1.5, 0, 0), (-1.42659, 0, 0.463526), (-1.21353, 0, 0.881678), (-0.881678, 0, 1.21353), (-0.463526, 0, 1.42659), (-4.47035e-08, 0, 1.5), (0.463526, 0, 1.42658), (0.881678, 0, 1.21353), (1.21353, 0, 0.881678), (1.42658, 0, 0.463526), (1.5, 0, 0), (1.40331, -0.154509, -0.455964), (1.19373, -0.154509, -0.867294), (0.867294, -0.154509, -1.19373), (0.455964, -0.154509, -1.40331), (0, -0.154509, -1.47553), (-0.455964, -0.154509, -1.40331), (-0.867294, -0.154509, -1.19373), (-1.19373, -0.154509, -0.867294), (-1.40331, -0.154509, -0.455963), (-1.47553, -0.154509, 0), (-1.40331, -0.154509, 0.455963), (-1.19373, -0.154509, 0.867294), (-0.867294, -0.154509, 1.19373), (-0.455963, -0.154509, 1.40331), (-4.39742e-08, -0.154509, 1.47553), (0.455963, -0.154509, 1.40331), (0.867294, -0.154509, 1.19373), (1.19373, -0.154509, 0.867294), (1.40331, -0.154509, 0.455963), (1.47553, -0.154509, 0), (1.33577, -0.293893, -0.434017), (1.13627, -0.293893, -0.82555), (0.82555, -0.293893, -1.13627), (0.434017, -0.293893, -1.33577), (0, -0.293893, -1.40451), (-0.434017, -0.293893, -1.33577), (-0.82555, -0.293893, -1.13627), (-1.13627, -0.293893, -0.82555), (-1.33577, -0.293893, -0.434017), (-1.40451, -0.293893, 0), (-1.33577, -0.293893, 0.434017), (-1.13627, -0.293893, 0.82555), (-0.82555, -0.293893, 1.13627), (-0.434017, -0.293893, 1.33577), (-4.18576e-08, -0.293893, 1.40451), (0.434017, -0.293893, 1.33577), (0.825549, -0.293893, 1.13627), (1.13627, -0.293893, 0.825549), (1.33577, -0.293893, 0.434017), (1.40451, -0.293893, 0), (1.23057, -0.404509, -0.399835), (1.04678, -0.404509, -0.760532), (0.760532, -0.404509, -1.04678), (0.399835, -0.404509, -1.23057), (0, -0.404509, -1.29389), (-0.399835, -0.404509, -1.23057), (-0.760531, -0.404509, -1.04678), (-1.04678, -0.404509, -0.760531), (-1.23057, -0.404509, -0.399835), (-1.29389, -0.404509, 0), (-1.23057, -0.404509, 0.399835), (-1.04678, -0.404509, 0.760531), (-0.760531, -0.404509, 1.04678), (-0.399835, -0.404509, 1.23057), (-3.8561e-08, -0.404509, 1.29389), (0.399835, -0.404509, 1.23057), (0.760531, -0.404509, 1.04678), (1.04678, -0.404509, 0.760531), (1.23057, -0.404509, 0.399835), (1.29389, -0.404509, 0), (1.098, -0.475528, -0.356763), (0.934018, -0.475528, -0.678604), (0.678604, -0.475528, -0.934018), (0.356763, -0.475528, -1.098), (0, -0.475528, -1.15451), (-0.356763, -0.475528, -1.098), (-0.678603, -0.475528, -0.934017), (-0.934017, -0.475528, -0.678603), (-1.098, -0.475528, -0.356763), (-1.15451, -0.475528, 0), (-1.098, -0.475528, 0.356763), (-0.934017, -0.475528, 0.678603), (-0.678603, -0.475528, 0.934017), (-0.356763, -0.475528, 1.098), (-3.4407e-08, -0.475528, 1.15451), (0.356763, -0.475528, 1.098), (0.678603, -0.475528, 0.934017), (0.934017, -0.475528, 0.678603), (1.098, -0.475528, 0.356763), (1.15451, -0.475528, 0), (0.951057, -0.5, -0.309017), (0.809018, -0.5, -0.587786), (0.587786, -0.5, -0.809017), (0.309017, -0.5, -0.951057), (0, -0.5, -1), (-0.309017, -0.5, -0.951057), (-0.587785, -0.5, -0.809017), (-0.809017, -0.5, -0.587785), (-0.951057, -0.5, -0.309017), (-1, -0.5, 0), (-0.951057, -0.5, 0.309017), (-0.809017, -0.5, 0.587785), (-0.587785, -0.5, 0.809017), (-0.309017, -0.5, 0.951057), (-2.98023e-08, -0.5, 1), (0.309017, -0.5, 0.951057), (0.587785, -0.5, 0.809017), (0.809017, -0.5, 0.587785), (0.951057, -0.5, 0.309017), (1, -0.5, 0), (0.804111, -0.475529, -0.261271), (0.684017, -0.475529, -0.496968), (0.496968, -0.475529, -0.684017), (0.261271, -0.475529, -0.804111), (0, -0.475529, -0.845492), (-0.261271, -0.475529, -0.80411), (-0.496968, -0.475529, -0.684017), (-0.684017, -0.475529, -0.496968), (-0.80411, -0.475529, -0.261271), (-0.845492, -0.475529, 0), (-0.80411, -0.475529, 0.261271), (-0.684017, -0.475529, 0.496967), (-0.496967, -0.475529, 0.684017), (-0.261271, -0.475529, 0.80411), (-2.51976e-08, -0.475529, 0.845492), (0.261271, -0.475529, 0.80411), (0.496967, -0.475529, 0.684017), (0.684017, -0.475529, 0.496967), (0.80411, -0.475529, 0.261271), (0.845491, -0.475529, 0), (0.671548, -0.404509, -0.218199), (0.571253, -0.404509, -0.41504), (0.41504, -0.404509, -0.571253), (0.218199, -0.404509, -0.671548), (0, -0.404509, -0.706108), (-0.218199, -0.404509, -0.671548), (-0.41504, -0.404509, -0.571253), (-0.571253, -0.404509, -0.41504), (-0.671548, -0.404509, -0.218199), (-0.706107, -0.404509, 0), (-0.671548, -0.404509, 0.218199), (-0.571253, -0.404509, 0.415039), (-0.415039, -0.404509, 0.571253), (-0.218199, -0.404509, 0.671548), (-2.10436e-08, -0.404509, 0.706107), (0.218199, -0.404509, 0.671548), (0.415039, -0.404509, 0.571253), (0.571253, -0.404509, 0.415039), (0.671548, -0.404509, 0.218199), (0.706107, -0.404509, 0), (0.566346, -0.293893, -0.184017), (0.481763, -0.293893, -0.350021), (0.350021, -0.293893, -0.481763), (0.184017, -0.293893, -0.566346), (0, -0.293893, -0.595492), (-0.184017, -0.293893, -0.566346), (-0.350021, -0.293893, -0.481763), (-0.481763, -0.293893, -0.350021), (-0.566346, -0.293893, -0.184017), (-0.595491, -0.293893, 0), (-0.566346, -0.293893, 0.184017), (-0.481763, -0.293893, 0.350021), (-0.350021, -0.293893, 0.481763), (-0.184017, -0.293893, 0.566346), (-1.7747e-08, -0.293893, 0.595491), (0.184017, -0.293893, 0.566346), (0.350021, -0.293893, 0.481763), (0.481763, -0.293893, 0.350021), (0.566346, -0.293893, 0.184017), (0.595491, -0.293893, 0), (0.498802, -0.154509, -0.162071), (0.424307, -0.154509, -0.308277), (0.308277, -0.154509, -0.424307), (0.162071, -0.154509, -0.498802), (0, -0.154509, -0.524472), (-0.162071, -0.154509, -0.498802), (-0.308277, -0.154509, -0.424306), (-0.424306, -0.154509, -0.308277), (-0.498802, -0.154509, -0.162071), (-0.524472, -0.154509, 0), (-0.498802, -0.154509, 0.162071), (-0.424306, -0.154509, 0.308277), (-0.308277, -0.154509, 0.424306), (-0.162071, -0.154509, 0.498802), (-1.56305e-08, -0.154509, 0.524471), (0.162071, -0.154509, 0.498802), (0.308277, -0.154509, 0.424306), (0.424306, -0.154509, 0.308277), (0.498802, -0.154509, 0.162071), (0.524471, -0.154509, 0)] + string primvars:__handleid = "${user:ModelInstance}_pTorus1" ( + interpolation = "constant" + ) + color3f[] primvars:displayColor = [(0.217638, 0.217638, 0.217638)] + float3[] primvars:ModelBuildRefPose = [(0.475529, 0, -0.154509), (0.404509, 0, -0.293893), (0.293893, 0, -0.404509), (0.154509, 0, -0.475529), (0, 0, -0.5), (-0.154509, 0, -0.475528), (-0.293893, 0, -0.404509), (-0.404509, 0, -0.293893), (-0.475528, 0, -0.154509), (-0.5, 0, 0), (-0.475528, 0, 0.154509), (-0.404509, 0, 0.293893), (-0.293893, 0, 0.404509), (-0.154509, 0, 0.475528), (-1.49012e-08, 0, 0.5), (0.154508, 0, 0.475528), (0.293893, 0, 0.404509), (0.404509, 0, 0.293893), (0.475528, 0, 0.154509), (0.5, 0, 0), (0.498803, 0.154509, -0.162071), (0.424307, 0.154509, -0.308277), (0.308277, 0.154509, -0.424307), (0.162071, 0.154509, -0.498803), (0, 0.154509, -0.524472), (-0.162071, 0.154509, -0.498803), (-0.308277, 0.154509, -0.424307), (-0.424307, 0.154509, -0.308277), (-0.498802, 0.154509, -0.162071), (-0.524472, 0.154509, 0), (-0.498802, 0.154509, 0.162071), (-0.424307, 0.154509, 0.308277), (-0.308277, 0.154509, 0.424307), (-0.162071, 0.154509, 0.498802), (-1.56305e-08, 0.154509, 0.524472), (0.162071, 0.154509, 0.498802), (0.308277, 0.154509, 0.424307), (0.424307, 0.154509, 0.308277), (0.498802, 0.154509, 0.162071), (0.524472, 0.154509, 0), (0.566346, 0.293893, -0.184017), (0.481763, 0.293893, -0.350021), (0.350021, 0.293893, -0.481763), (0.184017, 0.293893, -0.566346), (0, 0.293893, -0.595492), (-0.184017, 0.293893, -0.566346), (-0.350021, 0.293893, -0.481763), (-0.481763, 0.293893, -0.350021), (-0.566346, 0.293893, -0.184017), (-0.595492, 0.293893, 0), (-0.566346, 0.293893, 0.184017), (-0.481763, 0.293893, 0.350021), (-0.350021, 0.293893, 0.481763), (-0.184017, 0.293893, 0.566346), (-1.7747e-08, 0.293893, 0.595492), (0.184017, 0.293893, 0.566346), (0.350021, 0.293893, 0.481763), (0.481763, 0.293893, 0.350021), (0.566346, 0.293893, 0.184017), (0.595492, 0.293893, 0), (0.671548, 0.404509, -0.218199), (0.571253, 0.404509, -0.41504), (0.41504, 0.404509, -0.571253), (0.218199, 0.404509, -0.671548), (0, 0.404509, -0.706108), (-0.218199, 0.404509, -0.671548), (-0.41504, 0.404509, -0.571253), (-0.571253, 0.404509, -0.41504), (-0.671548, 0.404509, -0.218199), (-0.706108, 0.404509, 0), (-0.671548, 0.404509, 0.218199), (-0.571253, 0.404509, 0.41504), (-0.41504, 0.404509, 0.571253), (-0.218199, 0.404509, 0.671548), (-2.10436e-08, 0.404509, 0.706107), (0.218199, 0.404509, 0.671548), (0.41504, 0.404509, 0.571253), (0.571253, 0.404509, 0.41504), (0.671548, 0.404509, 0.218199), (0.706107, 0.404509, 0), (0.804111, 0.475528, -0.261271), (0.684017, 0.475528, -0.496968), (0.496968, 0.475528, -0.684017), (0.261271, 0.475528, -0.804111), (0, 0.475528, -0.845492), (-0.261271, 0.475528, -0.804111), (-0.496968, 0.475528, -0.684017), (-0.684017, 0.475528, -0.496968), (-0.80411, 0.475528, -0.261271), (-0.845492, 0.475528, 0), (-0.80411, 0.475528, 0.261271), (-0.684017, 0.475528, 0.496968), (-0.496968, 0.475528, 0.684017), (-0.261271, 0.475528, 0.80411), (-2.51976e-08, 0.475528, 0.845492), (0.261271, 0.475528, 0.80411), (0.496967, 0.475528, 0.684017), (0.684017, 0.475528, 0.496967), (0.80411, 0.475528, 0.261271), (0.845492, 0.475528, 0), (0.951057, 0.5, -0.309017), (0.809018, 0.5, -0.587786), (0.587786, 0.5, -0.809017), (0.309017, 0.5, -0.951057), (0, 0.5, -1), (-0.309017, 0.5, -0.951057), (-0.587785, 0.5, -0.809017), (-0.809017, 0.5, -0.587785), (-0.951057, 0.5, -0.309017), (-1, 0.5, 0), (-0.951057, 0.5, 0.309017), (-0.809017, 0.5, 0.587785), (-0.587785, 0.5, 0.809017), (-0.309017, 0.5, 0.951057), (-2.98023e-08, 0.5, 1), (0.309017, 0.5, 0.951057), (0.587785, 0.5, 0.809017), (0.809017, 0.5, 0.587785), (0.951057, 0.5, 0.309017), (1, 0.5, 0), (1.098, 0.475528, -0.356763), (0.934018, 0.475528, -0.678604), (0.678604, 0.475528, -0.934018), (0.356763, 0.475528, -1.098), (0, 0.475528, -1.15451), (-0.356763, 0.475528, -1.098), (-0.678603, 0.475528, -0.934017), (-0.934017, 0.475528, -0.678603), (-1.098, 0.475528, -0.356763), (-1.15451, 0.475528, 0), (-1.098, 0.475528, 0.356763), (-0.934017, 0.475528, 0.678603), (-0.678603, 0.475528, 0.934017), (-0.356763, 0.475528, 1.098), (-3.4407e-08, 0.475528, 1.15451), (0.356763, 0.475528, 1.098), (0.678603, 0.475528, 0.934017), (0.934017, 0.475528, 0.678603), (1.098, 0.475528, 0.356763), (1.15451, 0.475528, 0), (1.23057, 0.404509, -0.399835), (1.04678, 0.404509, -0.760531), (0.760531, 0.404509, -1.04678), (0.399835, 0.404509, -1.23057), (0, 0.404509, -1.29389), (-0.399835, 0.404509, -1.23057), (-0.760531, 0.404509, -1.04678), (-1.04678, 0.404509, -0.760531), (-1.23057, 0.404509, -0.399835), (-1.29389, 0.404509, 0), (-1.23057, 0.404509, 0.399835), (-1.04678, 0.404509, 0.760531), (-0.760531, 0.404509, 1.04678), (-0.399835, 0.404509, 1.23057), (-3.8561e-08, 0.404509, 1.29389), (0.399835, 0.404509, 1.23057), (0.760531, 0.404509, 1.04678), (1.04678, 0.404509, 0.760531), (1.23057, 0.404509, 0.399835), (1.29389, 0.404509, 0), (1.33577, 0.293893, -0.434017), (1.13627, 0.293893, -0.82555), (0.82555, 0.293893, -1.13627), (0.434017, 0.293893, -1.33577), (0, 0.293893, -1.40451), (-0.434017, 0.293893, -1.33577), (-0.82555, 0.293893, -1.13627), (-1.13627, 0.293893, -0.82555), (-1.33577, 0.293893, -0.434017), (-1.40451, 0.293893, 0), (-1.33577, 0.293893, 0.434017), (-1.13627, 0.293893, 0.82555), (-0.82555, 0.293893, 1.13627), (-0.434017, 0.293893, 1.33577), (-4.18576e-08, 0.293893, 1.40451), (0.434017, 0.293893, 1.33577), (0.825549, 0.293893, 1.13627), (1.13627, 0.293893, 0.825549), (1.33577, 0.293893, 0.434017), (1.40451, 0.293893, 0), (1.40331, 0.154509, -0.455964), (1.19373, 0.154509, -0.867294), (0.867294, 0.154509, -1.19373), (0.455964, 0.154509, -1.40331), (0, 0.154509, -1.47553), (-0.455964, 0.154509, -1.40331), (-0.867294, 0.154509, -1.19373), (-1.19373, 0.154509, -0.867294), (-1.40331, 0.154509, -0.455963), (-1.47553, 0.154509, 0), (-1.40331, 0.154509, 0.455963), (-1.19373, 0.154509, 0.867294), (-0.867294, 0.154509, 1.19373), (-0.455963, 0.154509, 1.40331), (-4.39742e-08, 0.154509, 1.47553), (0.455963, 0.154509, 1.40331), (0.867294, 0.154509, 1.19373), (1.19373, 0.154509, 0.867294), (1.40331, 0.154509, 0.455963), (1.47553, 0.154509, 0), (1.42659, 0, -0.463526), (1.21353, 0, -0.881678), (0.881678, 0, -1.21353), (0.463526, 0, -1.42659), (0, 0, -1.5), (-0.463526, 0, -1.42659), (-0.881678, 0, -1.21353), (-1.21353, 0, -0.881678), (-1.42659, 0, -0.463526), (-1.5, 0, 0), (-1.42659, 0, 0.463526), (-1.21353, 0, 0.881678), (-0.881678, 0, 1.21353), (-0.463526, 0, 1.42659), (-4.47035e-08, 0, 1.5), (0.463526, 0, 1.42658), (0.881678, 0, 1.21353), (1.21353, 0, 0.881678), (1.42658, 0, 0.463526), (1.5, 0, 0), (1.40331, -0.154509, -0.455964), (1.19373, -0.154509, -0.867294), (0.867294, -0.154509, -1.19373), (0.455964, -0.154509, -1.40331), (0, -0.154509, -1.47553), (-0.455964, -0.154509, -1.40331), (-0.867294, -0.154509, -1.19373), (-1.19373, -0.154509, -0.867294), (-1.40331, -0.154509, -0.455963), (-1.47553, -0.154509, 0), (-1.40331, -0.154509, 0.455963), (-1.19373, -0.154509, 0.867294), (-0.867294, -0.154509, 1.19373), (-0.455963, -0.154509, 1.40331), (-4.39742e-08, -0.154509, 1.47553), (0.455963, -0.154509, 1.40331), (0.867294, -0.154509, 1.19373), (1.19373, -0.154509, 0.867294), (1.40331, -0.154509, 0.455963), (1.47553, -0.154509, 0), (1.33577, -0.293893, -0.434017), (1.13627, -0.293893, -0.82555), (0.82555, -0.293893, -1.13627), (0.434017, -0.293893, -1.33577), (0, -0.293893, -1.40451), (-0.434017, -0.293893, -1.33577), (-0.82555, -0.293893, -1.13627), (-1.13627, -0.293893, -0.82555), (-1.33577, -0.293893, -0.434017), (-1.40451, -0.293893, 0), (-1.33577, -0.293893, 0.434017), (-1.13627, -0.293893, 0.82555), (-0.82555, -0.293893, 1.13627), (-0.434017, -0.293893, 1.33577), (-4.18576e-08, -0.293893, 1.40451), (0.434017, -0.293893, 1.33577), (0.825549, -0.293893, 1.13627), (1.13627, -0.293893, 0.825549), (1.33577, -0.293893, 0.434017), (1.40451, -0.293893, 0), (1.23057, -0.404509, -0.399835), (1.04678, -0.404509, -0.760532), (0.760532, -0.404509, -1.04678), (0.399835, -0.404509, -1.23057), (0, -0.404509, -1.29389), (-0.399835, -0.404509, -1.23057), (-0.760531, -0.404509, -1.04678), (-1.04678, -0.404509, -0.760531), (-1.23057, -0.404509, -0.399835), (-1.29389, -0.404509, 0), (-1.23057, -0.404509, 0.399835), (-1.04678, -0.404509, 0.760531), (-0.760531, -0.404509, 1.04678), (-0.399835, -0.404509, 1.23057), (-3.8561e-08, -0.404509, 1.29389), (0.399835, -0.404509, 1.23057), (0.760531, -0.404509, 1.04678), (1.04678, -0.404509, 0.760531), (1.23057, -0.404509, 0.399835), (1.29389, -0.404509, 0), (1.098, -0.475528, -0.356763), (0.934018, -0.475528, -0.678604), (0.678604, -0.475528, -0.934018), (0.356763, -0.475528, -1.098), (0, -0.475528, -1.15451), (-0.356763, -0.475528, -1.098), (-0.678603, -0.475528, -0.934017), (-0.934017, -0.475528, -0.678603), (-1.098, -0.475528, -0.356763), (-1.15451, -0.475528, 0), (-1.098, -0.475528, 0.356763), (-0.934017, -0.475528, 0.678603), (-0.678603, -0.475528, 0.934017), (-0.356763, -0.475528, 1.098), (-3.4407e-08, -0.475528, 1.15451), (0.356763, -0.475528, 1.098), (0.678603, -0.475528, 0.934017), (0.934017, -0.475528, 0.678603), (1.098, -0.475528, 0.356763), (1.15451, -0.475528, 0), (0.951057, -0.5, -0.309017), (0.809018, -0.5, -0.587786), (0.587786, -0.5, -0.809017), (0.309017, -0.5, -0.951057), (0, -0.5, -1), (-0.309017, -0.5, -0.951057), (-0.587785, -0.5, -0.809017), (-0.809017, -0.5, -0.587785), (-0.951057, -0.5, -0.309017), (-1, -0.5, 0), (-0.951057, -0.5, 0.309017), (-0.809017, -0.5, 0.587785), (-0.587785, -0.5, 0.809017), (-0.309017, -0.5, 0.951057), (-2.98023e-08, -0.5, 1), (0.309017, -0.5, 0.951057), (0.587785, -0.5, 0.809017), (0.809017, -0.5, 0.587785), (0.951057, -0.5, 0.309017), (1, -0.5, 0), (0.804111, -0.475529, -0.261271), (0.684017, -0.475529, -0.496968), (0.496968, -0.475529, -0.684017), (0.261271, -0.475529, -0.804111), (0, -0.475529, -0.845492), (-0.261271, -0.475529, -0.80411), (-0.496968, -0.475529, -0.684017), (-0.684017, -0.475529, -0.496968), (-0.80411, -0.475529, -0.261271), (-0.845492, -0.475529, 0), (-0.80411, -0.475529, 0.261271), (-0.684017, -0.475529, 0.496967), (-0.496967, -0.475529, 0.684017), (-0.261271, -0.475529, 0.80411), (-2.51976e-08, -0.475529, 0.845492), (0.261271, -0.475529, 0.80411), (0.496967, -0.475529, 0.684017), (0.684017, -0.475529, 0.496967), (0.80411, -0.475529, 0.261271), (0.845491, -0.475529, 0), (0.671548, -0.404509, -0.218199), (0.571253, -0.404509, -0.41504), (0.41504, -0.404509, -0.571253), (0.218199, -0.404509, -0.671548), (0, -0.404509, -0.706108), (-0.218199, -0.404509, -0.671548), (-0.41504, -0.404509, -0.571253), (-0.571253, -0.404509, -0.41504), (-0.671548, -0.404509, -0.218199), (-0.706107, -0.404509, 0), (-0.671548, -0.404509, 0.218199), (-0.571253, -0.404509, 0.415039), (-0.415039, -0.404509, 0.571253), (-0.218199, -0.404509, 0.671548), (-2.10436e-08, -0.404509, 0.706107), (0.218199, -0.404509, 0.671548), (0.415039, -0.404509, 0.571253), (0.571253, -0.404509, 0.415039), (0.671548, -0.404509, 0.218199), (0.706107, -0.404509, 0), (0.566346, -0.293893, -0.184017), (0.481763, -0.293893, -0.350021), (0.350021, -0.293893, -0.481763), (0.184017, -0.293893, -0.566346), (0, -0.293893, -0.595492), (-0.184017, -0.293893, -0.566346), (-0.350021, -0.293893, -0.481763), (-0.481763, -0.293893, -0.350021), (-0.566346, -0.293893, -0.184017), (-0.595491, -0.293893, 0), (-0.566346, -0.293893, 0.184017), (-0.481763, -0.293893, 0.350021), (-0.350021, -0.293893, 0.481763), (-0.184017, -0.293893, 0.566346), (-1.7747e-08, -0.293893, 0.595491), (0.184017, -0.293893, 0.566346), (0.350021, -0.293893, 0.481763), (0.481763, -0.293893, 0.350021), (0.566346, -0.293893, 0.184017), (0.595491, -0.293893, 0), (0.498802, -0.154509, -0.162071), (0.424307, -0.154509, -0.308277), (0.308277, -0.154509, -0.424307), (0.162071, -0.154509, -0.498802), (0, -0.154509, -0.524472), (-0.162071, -0.154509, -0.498802), (-0.308277, -0.154509, -0.424306), (-0.424306, -0.154509, -0.308277), (-0.498802, -0.154509, -0.162071), (-0.524472, -0.154509, 0), (-0.498802, -0.154509, 0.162071), (-0.424306, -0.154509, 0.308277), (-0.308277, -0.154509, 0.424306), (-0.162071, -0.154509, 0.498802), (-1.56305e-08, -0.154509, 0.524471), (0.162071, -0.154509, 0.498802), (0.308277, -0.154509, 0.424306), (0.424306, -0.154509, 0.308277), (0.498802, -0.154509, 0.162071), (0.524471, -0.154509, 0)] ( + interpolation = "vertex" + ) + float[] primvars:ptexFaceIndex = [0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63, 64, 64, 64, 64, 65, 65, 65, 65, 66, 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 69, 69, 69, 70, 70, 70, 70, 71, 71, 71, 71, 72, 72, 72, 72, 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, 77, 78, 78, 78, 78, 79, 79, 79, 79, 80, 80, 80, 80, 81, 81, 81, 81, 82, 82, 82, 82, 83, 83, 83, 83, 84, 84, 84, 84, 85, 85, 85, 85, 86, 86, 86, 86, 87, 87, 87, 87, 88, 88, 88, 88, 89, 89, 89, 89, 90, 90, 90, 90, 91, 91, 91, 91, 92, 92, 92, 92, 93, 93, 93, 93, 94, 94, 94, 94, 95, 95, 95, 95, 96, 96, 96, 96, 97, 97, 97, 97, 98, 98, 98, 98, 99, 99, 99, 99, 100, 100, 100, 100, 101, 101, 101, 101, 102, 102, 102, 102, 103, 103, 103, 103, 104, 104, 104, 104, 105, 105, 105, 105, 106, 106, 106, 106, 107, 107, 107, 107, 108, 108, 108, 108, 109, 109, 109, 109, 110, 110, 110, 110, 111, 111, 111, 111, 112, 112, 112, 112, 113, 113, 113, 113, 114, 114, 114, 114, 115, 115, 115, 115, 116, 116, 116, 116, 117, 117, 117, 117, 118, 118, 118, 118, 119, 119, 119, 119, 120, 120, 120, 120, 121, 121, 121, 121, 122, 122, 122, 122, 123, 123, 123, 123, 124, 124, 124, 124, 125, 125, 125, 125, 126, 126, 126, 126, 127, 127, 127, 127, 128, 128, 128, 128, 129, 129, 129, 129, 130, 130, 130, 130, 131, 131, 131, 131, 132, 132, 132, 132, 133, 133, 133, 133, 134, 134, 134, 134, 135, 135, 135, 135, 136, 136, 136, 136, 137, 137, 137, 137, 138, 138, 138, 138, 139, 139, 139, 139, 140, 140, 140, 140, 141, 141, 141, 141, 142, 142, 142, 142, 143, 143, 143, 143, 144, 144, 144, 144, 145, 145, 145, 145, 146, 146, 146, 146, 147, 147, 147, 147, 148, 148, 148, 148, 149, 149, 149, 149, 150, 150, 150, 150, 151, 151, 151, 151, 152, 152, 152, 152, 153, 153, 153, 153, 154, 154, 154, 154, 155, 155, 155, 155, 156, 156, 156, 156, 157, 157, 157, 157, 158, 158, 158, 158, 159, 159, 159, 159, 160, 160, 160, 160, 161, 161, 161, 161, 162, 162, 162, 162, 163, 163, 163, 163, 164, 164, 164, 164, 165, 165, 165, 165, 166, 166, 166, 166, 167, 167, 167, 167, 168, 168, 168, 168, 169, 169, 169, 169, 170, 170, 170, 170, 171, 171, 171, 171, 172, 172, 172, 172, 173, 173, 173, 173, 174, 174, 174, 174, 175, 175, 175, 175, 176, 176, 176, 176, 177, 177, 177, 177, 178, 178, 178, 178, 179, 179, 179, 179, 180, 180, 180, 180, 181, 181, 181, 181, 182, 182, 182, 182, 183, 183, 183, 183, 184, 184, 184, 184, 185, 185, 185, 185, 186, 186, 186, 186, 187, 187, 187, 187, 188, 188, 188, 188, 189, 189, 189, 189, 190, 190, 190, 190, 191, 191, 191, 191, 192, 192, 192, 192, 193, 193, 193, 193, 194, 194, 194, 194, 195, 195, 195, 195, 196, 196, 196, 196, 197, 197, 197, 197, 198, 198, 198, 198, 199, 199, 199, 199, 200, 200, 200, 200, 201, 201, 201, 201, 202, 202, 202, 202, 203, 203, 203, 203, 204, 204, 204, 204, 205, 205, 205, 205, 206, 206, 206, 206, 207, 207, 207, 207, 208, 208, 208, 208, 209, 209, 209, 209, 210, 210, 210, 210, 211, 211, 211, 211, 212, 212, 212, 212, 213, 213, 213, 213, 214, 214, 214, 214, 215, 215, 215, 215, 216, 216, 216, 216, 217, 217, 217, 217, 218, 218, 218, 218, 219, 219, 219, 219, 220, 220, 220, 220, 221, 221, 221, 221, 222, 222, 222, 222, 223, 223, 223, 223, 224, 224, 224, 224, 225, 225, 225, 225, 226, 226, 226, 226, 227, 227, 227, 227, 228, 228, 228, 228, 229, 229, 229, 229, 230, 230, 230, 230, 231, 231, 231, 231, 232, 232, 232, 232, 233, 233, 233, 233, 234, 234, 234, 234, 235, 235, 235, 235, 236, 236, 236, 236, 237, 237, 237, 237, 238, 238, 238, 238, 239, 239, 239, 239, 240, 240, 240, 240, 241, 241, 241, 241, 242, 242, 242, 242, 243, 243, 243, 243, 244, 244, 244, 244, 245, 245, 245, 245, 246, 246, 246, 246, 247, 247, 247, 247, 248, 248, 248, 248, 249, 249, 249, 249, 250, 250, 250, 250, 251, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254, 254, 254, 254, 255, 255, 255, 255, 256, 256, 256, 256, 257, 257, 257, 257, 258, 258, 258, 258, 259, 259, 259, 259, 260, 260, 260, 260, 261, 261, 261, 261, 262, 262, 262, 262, 263, 263, 263, 263, 264, 264, 264, 264, 265, 265, 265, 265, 266, 266, 266, 266, 267, 267, 267, 267, 268, 268, 268, 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, 272, 272, 273, 273, 273, 273, 274, 274, 274, 274, 275, 275, 275, 275, 276, 276, 276, 276, 277, 277, 277, 277, 278, 278, 278, 278, 279, 279, 279, 279, 280, 280, 280, 280, 281, 281, 281, 281, 282, 282, 282, 282, 283, 283, 283, 283, 284, 284, 284, 284, 285, 285, 285, 285, 286, 286, 286, 286, 287, 287, 287, 287, 288, 288, 288, 288, 289, 289, 289, 289, 290, 290, 290, 290, 291, 291, 291, 291, 292, 292, 292, 292, 293, 293, 293, 293, 294, 294, 294, 294, 295, 295, 295, 295, 296, 296, 296, 296, 297, 297, 297, 297, 298, 298, 298, 298, 299, 299, 299, 299, 300, 300, 300, 300, 301, 301, 301, 301, 302, 302, 302, 302, 303, 303, 303, 303, 304, 304, 304, 304, 305, 305, 305, 305, 306, 306, 306, 306, 307, 307, 307, 307, 308, 308, 308, 308, 309, 309, 309, 309, 310, 310, 310, 310, 311, 311, 311, 311, 312, 312, 312, 312, 313, 313, 313, 313, 314, 314, 314, 314, 315, 315, 315, 315, 316, 316, 316, 316, 317, 317, 317, 317, 318, 318, 318, 318, 319, 319, 319, 319, 320, 320, 320, 320, 321, 321, 321, 321, 322, 322, 322, 322, 323, 323, 323, 323, 324, 324, 324, 324, 325, 325, 325, 325, 326, 326, 326, 326, 327, 327, 327, 327, 328, 328, 328, 328, 329, 329, 329, 329, 330, 330, 330, 330, 331, 331, 331, 331, 332, 332, 332, 332, 333, 333, 333, 333, 334, 334, 334, 334, 335, 335, 335, 335, 336, 336, 336, 336, 337, 337, 337, 337, 338, 338, 338, 338, 339, 339, 339, 339, 340, 340, 340, 340, 341, 341, 341, 341, 342, 342, 342, 342, 343, 343, 343, 343, 344, 344, 344, 344, 345, 345, 345, 345, 346, 346, 346, 346, 347, 347, 347, 347, 348, 348, 348, 348, 349, 349, 349, 349, 350, 350, 350, 350, 351, 351, 351, 351, 352, 352, 352, 352, 353, 353, 353, 353, 354, 354, 354, 354, 355, 355, 355, 355, 356, 356, 356, 356, 357, 357, 357, 357, 358, 358, 358, 358, 359, 359, 359, 359, 360, 360, 360, 360, 361, 361, 361, 361, 362, 362, 362, 362, 363, 363, 363, 363, 364, 364, 364, 364, 365, 365, 365, 365, 366, 366, 366, 366, 367, 367, 367, 367, 368, 368, 368, 368, 369, 369, 369, 369, 370, 370, 370, 370, 371, 371, 371, 371, 372, 372, 372, 372, 373, 373, 373, 373, 374, 374, 374, 374, 375, 375, 375, 375, 376, 376, 376, 376, 377, 377, 377, 377, 378, 378, 378, 378, 379, 379, 379, 379, 380, 380, 380, 380, 381, 381, 381, 381, 382, 382, 382, 382, 383, 383, 383, 383, 384, 384, 384, 384, 385, 385, 385, 385, 386, 386, 386, 386, 387, 387, 387, 387, 388, 388, 388, 388, 389, 389, 389, 389, 390, 390, 390, 390, 391, 391, 391, 391, 392, 392, 392, 392, 393, 393, 393, 393, 394, 394, 394, 394, 395, 395, 395, 395, 396, 396, 396, 396, 397, 397, 397, 397, 398, 398, 398, 398, 399, 399, 399, 399] ( + interpolation = "faceVarying" + ) + int primvars:ptexFaceOffset = 706 ( + interpolation = "constant" + ) + float[] primvars:u_map1 = [0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001, 0.05, 0, 0, 0.05, 0.1, 0.05, 0.05, 0.1, 0.15, 0.1, 0.1, 0.15, 0.2, 0.15, 0.15, 0.2, 0.25, 0.2, 0.2, 0.25, 0.3, 0.25, 0.25, 0.3, 0.35000002, 0.3, 0.3, 0.35000002, 0.40000004, 0.35000002, 0.35000002, 0.40000004, 0.45000005, 0.40000004, 0.40000004, 0.45000005, 0.50000006, 0.45000005, 0.45000005, 0.50000006, 0.5500001, 0.50000006, 0.50000006, 0.5500001, 0.6000001, 0.5500001, 0.5500001, 0.6000001, 0.6500001, 0.6000001, 0.6000001, 0.6500001, 0.7000001, 0.6500001, 0.6500001, 0.7000001, 0.7500001, 0.7000001, 0.7000001, 0.7500001, 0.80000013, 0.7500001, 0.7500001, 0.80000013, 0.85000014, 0.80000013, 0.80000013, 0.85000014, 0.90000015, 0.85000014, 0.85000014, 0.90000015, 0.95000017, 0.90000015, 0.90000015, 0.95000017, 1.0000001, 0.95000017, 0.95000017, 1.0000001] ( + interpolation = "faceVarying" + ) + float[] primvars:v_map1 = [1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 1, 1, 0.95, 0.95, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.95, 0.95, 0.9, 0.9, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.9, 0.9, 0.84999996, 0.84999996, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.84999996, 0.84999996, 0.79999995, 0.79999995, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.79999995, 0.79999995, 0.74999994, 0.74999994, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.74999994, 0.74999994, 0.6999999, 0.6999999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6999999, 0.6999999, 0.6499999, 0.6499999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.6499999, 0.6499999, 0.5999999, 0.5999999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5999999, 0.5999999, 0.5499999, 0.5499999, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.5499999, 0.5499999, 0.49999988, 0.49999988, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.49999988, 0.49999988, 0.44999987, 0.44999987, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.44999987, 0.44999987, 0.39999986, 0.39999986, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.39999986, 0.39999986, 0.34999985, 0.34999985, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.34999985, 0.34999985, 0.29999983, 0.29999983, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.29999983, 0.29999983, 0.24999984, 0.24999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.24999984, 0.24999984, 0.19999984, 0.19999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.19999984, 0.19999984, 0.14999984, 0.14999984, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.14999984, 0.14999984, 0.099999845, 0.099999845, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.099999845, 0.099999845, 0.049999844, 0.049999844, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7, 0.049999844, 0.049999844, -1.5646219e-7, -1.5646219e-7] ( + interpolation = "faceVarying" + ) + } + } + + over "Sim" ( + active = false + ) + { + } + variantSet "modelingVariant" = { + "ALL_VARIANTS" { + + } + "Cone" { + over "Geom" + { + over "pCube1" ( + active = false + ) + { + } + + over "pCylinder1" ( + active = false + ) + { + } + + over "pSphere1" ( + active = false + ) + { + } + + over "pTorus1" ( + active = false + ) + { + } + } + + } + "Cube" { + over "Geom" + { + over "pCone1" ( + active = false + ) + { + } + + over "pCylinder1" ( + active = false + ) + { + } + + over "pSphere1" ( + active = false + ) + { + } + + over "pTorus1" ( + active = false + ) + { + } + } + + } + "Cylinder" { + over "Geom" + { + over "pCone1" ( + active = false + ) + { + } + + over "pCube1" ( + active = false + ) + { + } + + over "pSphere1" ( + active = false + ) + { + } + + over "pTorus1" ( + active = false + ) + { + } + } + + } + "Sphere" { + over "Geom" + { + over "pCone1" ( + active = false + ) + { + } + + over "pCube1" ( + active = false + ) + { + } + + over "pCylinder1" ( + active = false + ) + { + } + + over "pTorus1" ( + active = false + ) + { + } + } + + } + "Torus" { + over "Geom" + { + over "pCone1" ( + active = false + ) + { + } + + over "pCube1" ( + active = false + ) + { + } + + over "pCylinder1" ( + active = false + ) + { + } + + over "pSphere1" ( + active = false + ) + { + } + } + + } + } +} + diff --git a/testsuite/test_0017/ref/reference.log b/testsuite/test_0017/ref/reference.log new file mode 100755 index 0000000000..da62a18244 --- /dev/null +++ b/testsuite/test_0017/ref/reference.log @@ -0,0 +1,194 @@ +00:00:00 47MB | log started Mon Jun 17 12:48:03 2019 +00:00:00 47MB | Arnold 5.3.1.0 [d6b4954e] darwin clang-5.0.0 oiio-2.1.0 osl-1.11.0 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 2019/05/20 14:44:15 +00:00:00 47MB | running on Pals-MacBook-Pro.local, pid=33870 +00:00:00 47MB | 1 x Intel(R) Core(TM) i7-8850H CPU @ 2.60GHz (6 cores, 12 logical) with 32768MB +00:00:00 47MB | macOS 10.14.5 "Mojave", Darwin kernel 18.6.0 +00:00:00 47MB | soft limit for open files raised from 256 to 10238 +00:00:00 47MB | +00:00:00 47MB | loading plugins from /Users/sirpalee/projects/arnold_usd/build/darwin_x86_64/gcc_opt/usd-0.19.7_arnold-5.3.1.0/procedural ... +00:00:00 47MB | usd_proc.dylib: usd uses Arnold 5.3.1.0 +00:00:00 47MB | loaded 1 plugins from 1 lib(s) in 0:00.02 +00:00:00 47MB | loading plugins from /Users/sirpalee/apps/arnold/bin/./../plugins ... +00:00:00 47MB | cryptomatte.dylib: cryptomatte uses Arnold 5.3.1.0 +00:00:00 47MB | cryptomatte.dylib: cryptomatte_filter uses Arnold 5.3.1.0 +00:00:00 47MB | cryptomatte.dylib: cryptomatte_manifest_driver uses Arnold 5.3.1.0 +00:00:00 47MB | alembic_proc.dylib: alembic uses Arnold 5.3.1.0 +00:00:00 47MB | loaded 4 plugins from 2 lib(s) in 0:00.01 +00:00:00 47MB | [kick] command: /Users/sirpalee/apps/arnold/bin/kick test.ass -dw -r 160 120 -bs 16 -o testrender.tif -set driver_tiff.dither false -dp -v 6 +00:00:00 47MB | loading plugins from . ... +00:00:00 47MB | no plugins loaded +00:00:00 47MB | [metadata] loading metadata file: test.ass +00:00:00 47MB | [ass] loading test.ass ... +00:00:00 47MB | [ass] read 1894 bytes, 6 nodes in 0:00.00 +00:00:00 47MB | [kick] applying 1 attr value override +00:00:00 47MB | +00:00:00 48MB | authorizing with default license managers: rlm, clm ... +00:00:00 48MB WARNING | rendering with watermarks because of failed authorization: +00:00:00 48MB | [rlm] error initializing license system: +00:00:00 48MB | [rlm] * Can't read license data (-102) +00:00:00 48MB | [clm] license server was not set (51) +00:00:00 48MB | environment variables: +00:00:00 48MB | ARNOLD_LICENSE_MANAGER = (not set) +00:00:00 48MB | [rlm] solidangle_LICENSE = (not set) +00:00:00 48MB | [rlm] RLM_LICENSE = (not set) +00:00:00 48MB | [clm] ADSKFLEX_LICENSE_FILE = (not set) +00:00:00 48MB | [clm] LM_LICENSE_FILE = (not set) +00:00:00 48MB | +00:00:00 48MB | [color_manager] no color manager is active +00:00:00 48MB | [color_manager] rendering color space is "linear" with declared chromaticities: +00:00:00 48MB | r(0.6400, 0.3300) g(0.3000, 0.6000) b(0.1500, 0.0600) and w(0.3127, 0.3290) +00:00:00 59MB | +00:00:00 59MB | there are 1 light and 2 objects: +00:00:00 59MB | 1 persp_camera +00:00:00 59MB | 1 distant_light +00:00:00 59MB | 1 utility +00:00:00 59MB | 1 driver_tiff +00:00:00 59MB | 1 gaussian_filter +00:00:00 59MB | 1 list_aggregate +00:00:00 59MB | 1 usd +00:00:00 59MB | +00:00:00 59MB | rendering image at 160 x 120, 1 AA sample +00:00:00 59MB | AA samples max +00:00:00 59MB | AA sample clamp +00:00:00 59MB | diffuse +00:00:00 59MB | specular +00:00:00 59MB | transmission samples 2 / depth 2 +00:00:00 59MB | volume indirect +00:00:00 59MB | total depth 10 +00:00:00 59MB | bssrdf samples 2 +00:00:00 59MB | transparency depth 10 +00:00:00 59MB | initializing 8 nodes ... +00:00:00 69MB | [proc] aiUsdShape2: loaded 1 nodes (1 objects, 0 shaders) +00:00:00 69MB | creating root object list ... +00:00:00 69MB | node initialization done in 0:00.05 (multithreaded) +00:00:00 69MB | updating 10 nodes ... +00:00:00 69MB | directionalLightShape1: distant_light using 1 sample, 2 volume samples +00:00:00 69MB | scene bounds: (-1.5 -7.76828718 -1.5) -> (1.5 -6.76828718 1.5) +00:00:00 69MB | node update done in 0:00.00 (multithreaded) +00:00:00 70MB | [aov] parsing 1 output statements ... +00:00:00 70MB | [aov] registered driver: "mydriver" (driver_tiff) +00:00:00 70MB | [aov] * "RGBA" of type RGBA filtered by "myfilter" (gaussian_filter) +00:00:00 70MB | [aov] done preparing 2 AOVs for 1 output to 1 driver (0 deep AOVs) +00:00:00 70MB | starting 12 bucket workers of size 16x16 ... +00:00:00 71MB | [subdiv] /ExampleModelingVariants/Geom/pTorus1: regular subdivision done - 1 iterations: 400 faces => 1600 quads - 0:00.00 +00:00:00 72MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1600 prims, 1 key +00:00:00 72MB | 0% done - 13 rays/pixel +00:00:00 72MB | 5% done - 0 rays/pixel +00:00:00 72MB | 10% done - 0 rays/pixel +00:00:00 72MB | 15% done - 3 rays/pixel +00:00:00 72MB | 20% done - 0 rays/pixel +00:00:00 72MB | 25% done - 1 rays/pixel +00:00:00 72MB | 30% done - 2 rays/pixel +00:00:00 72MB | 35% done - 1 rays/pixel +00:00:00 72MB | 40% done - 1 rays/pixel +00:00:00 72MB | 45% done - 1 rays/pixel +00:00:00 72MB | 50% done - 1 rays/pixel +00:00:00 72MB | 55% done - 0 rays/pixel +00:00:00 72MB | 60% done - 2 rays/pixel +00:00:00 72MB | 65% done - 1 rays/pixel +00:00:00 72MB | 70% done - 2 rays/pixel +00:00:00 72MB | 75% done - 1 rays/pixel +00:00:00 72MB | 80% done - 2 rays/pixel +00:00:00 72MB | 85% done - 0 rays/pixel +00:00:00 72MB | 90% done - 1 rays/pixel +00:00:00 72MB | 95% done - 1 rays/pixel +00:00:00 72MB | 100% done - 0 rays/pixel +00:00:00 72MB | render done in 0:00.006 +00:00:00 72MB | [driver_tiff] writing file `testrender.tif' +00:00:00 73MB | render done +00:00:00 73MB | +00:00:00 73MB | ----------------------------------------------------------------------------------- +00:00:00 73MB | scene creation time 0:00.05 machine utilization (6.94%) +00:00:00 73MB | plugin loading 0:00.04 +00:00:00 73MB | ----------------------------------------------------------------------------------- +00:00:00 73MB | frame time 0:00.06 machine utilization (70.65%) +00:00:00 73MB | node init 0:00.05 +00:00:00 73MB | ----------------------------------------------------------------------------------- +00:00:00 73MB | top session self-times by category +00:00:00 73MB | InitializeNodes 0:00.04 (63.95%) +00:00:00 73MB | worker waiting 0:00.00 (10.12%) +00:00:00 73MB | initializeAllNodes 0:00.00 ( 5.83%) +00:00:00 73MB | node_init 0:00.00 ( 5.83%) +00:00:00 73MB | aiUsdShape2 0:00.00 ( 5.55%) +00:00:00 73MB | Plugin loader 0:00.00 ( 5.23%) +00:00:00 73MB | BVH::build 0:00.00 ( 3.17%) +00:00:00 73MB | thread blocked 0:00.00 ( 2.97%) +00:00:00 73MB | ----------------------------------------------------------------------------------- +00:00:00 73MB | top session self-times by node +00:00:00 73MB | InitializeNodes 0:00.04 (63.95%) +00:00:00 73MB | worker waiting 0:00.00 (10.12%) +00:00:00 73MB | polymesh:/ExampleModelingVariants/Geom/pTorus1 0:00.00 ( 6.42%) +00:00:00 73MB | BVH::build 0:00.00 ( 3.17%) +00:00:00 73MB | thread blocked 0:00.00 ( 2.16%) +00:00:00 73MB | polymesh::intersect 0:00.00 ( 0.58%) +00:00:00 73MB | initializeAllNodes 0:00.00 ( 5.83%) +00:00:00 73MB | usd:aiUsdShape2 (node_init) 0:00.00 ( 5.55%) +00:00:00 73MB | Plugin loader 0:00.00 ( 5.23%) +00:00:00 73MB | ----------------------------------------------------------------------------------- +00:00:00 73MB | peak CPU memory used 73.07MB +00:00:00 73MB | at startup 36.82MB +00:00:00 73MB | plugins 7.14MB +00:00:00 73MB | AOV samples 0.73MB +00:00:00 73MB | output buffers 0.12MB +00:00:00 73MB | framebuffers 0.31MB +00:00:00 73MB | node overhead 0.00MB +00:00:00 73MB | message passing 0.02MB +00:00:00 73MB | memory pools 16.05MB +00:00:00 73MB | geometry 0.17MB +00:00:00 73MB | subdivs 0.17MB +00:00:00 73MB | accel. structs 0.05MB +00:00:00 73MB | strings 12.00MB +00:00:00 73MB | profiler 0.00MB +00:00:00 73MB | unaccounted -0.37MB +00:00:00 73MB | ----------------------------------------------------------------------------------- +00:00:00 73MB | ray counts ( /pixel, /sample) (% total) (avg. hits) (max hits) +00:00:00 73MB | camera 24160 ( 1.26, 1.00) (100.00%) ( 0.50) ( 1) +00:00:00 73MB | total 24160 ( 1.26, 1.00) (100.00%) ( 0.50) ( 1) +00:00:00 73MB | by ray depth: 0 +00:00:00 73MB | total 100.0% +00:00:00 73MB | ----------------------------------------------------------------------------------- +00:00:00 73MB | shader calls ( /pixel, /sample) (% total) +00:00:00 73MB | primary 12149 ( 0.63, 0.50) (100.00%) +00:00:00 73MB | total 12149 ( 0.63, 0.50) (100.00%) +00:00:00 73MB | by ray depth: 0 +00:00:00 73MB | total 100.0% +00:00:00 73MB | ----------------------------------------------------------------------------------- +00:00:00 73MB | geometry (% hit ) (instances) ( init mem, final mem) +00:00:00 73MB | lists 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:00 73MB | procs 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:00 73MB | subdivs 1 (100.0%) ( 0) ( 0.05, 0.17) +00:00:00 73MB | ----------------------------------------------------------------------------------- +00:00:00 73MB | geometric elements ( min) ( avg.) ( max) +00:00:00 73MB | objects (procs) 1 ( 1) ( 1.0) ( 1) +00:00:00 73MB | subdiv patches 400 ( 400) ( 400.0) ( 400) +00:00:00 73MB | ----------------------------------------------------------------------------------- +00:00:00 73MB | triangle tessellation ( min) ( avg.) ( max) (/ element) (% total) +00:00:00 73MB | subdivs 3200 ( 3200) ( 3200.0) ( 3200) ( 8.00) (100.00%) +00:00:00 73MB | iterations 1 3200 ( 3200) ( 3200.0) ( 3200) ( 8.00) (100.00%) +00:00:00 73MB | unique triangles 3200 +00:00:00 73MB | CPU memory use 0.17MB +00:00:00 73MB | vertices 0.02MB +00:00:00 73MB | vertex indices 0.01MB +00:00:00 73MB | packed normals 0.01MB +00:00:00 73MB | normal indices 0.00MB +00:00:00 73MB | uniform indices 0.00MB +00:00:00 73MB | userdata 0.13MB +00:00:00 73MB | largest polymeshes by triangle count +00:00:00 73MB | 3200 tris -- /ExampleModelingVariants/Geom/pTorus1 +00:00:00 73MB | ----------------------------------------------------------------------------------- +00:00:00 73MB | acceleration structures: (% total) +00:00:00 73MB | list 2 ( 66.67%) +00:00:00 73MB | bvh 1 ( 33.33%) +00:00:00 73MB | total 3 (100.00%) +00:00:00 73MB | ----------------------------------------------------------------------------------- +00:00:00 73MB | number of warnings, warning type: +00:00:00 73MB | 1: rendering with watermarks because of failed authorization: +00:00:00 73MB | ----------------------------------------------------------------------------------- +00:00:00 73MB | +00:00:00 73MB | releasing resources +00:00:00 72MB | unloading 3 plugins +00:00:00 72MB | closing usd_proc.dylib ... +00:00:00 72MB | closing cryptomatte.dylib ... +00:00:00 72MB | closing alembic_proc.dylib ... +00:00:00 72MB | unloading plugins done +00:00:00 72MB | Arnold shutdown diff --git a/testsuite/test_0017/ref/reference.tif b/testsuite/test_0017/ref/reference.tif new file mode 100755 index 0000000000..7942589bed Binary files /dev/null and b/testsuite/test_0017/ref/reference.tif differ diff --git a/testsuite/test_0018/README b/testsuite/test_0018/README new file mode 100755 index 0000000000..3699e75c25 --- /dev/null +++ b/testsuite/test_0018/README @@ -0,0 +1,3 @@ +Test animated Xform (#8499) + +author: sebastien ortega diff --git a/testsuite/test_0018/data/sphere.usd b/testsuite/test_0018/data/sphere.usd new file mode 100755 index 0000000000..4936f54bd8 --- /dev/null +++ b/testsuite/test_0018/data/sphere.usd @@ -0,0 +1,52 @@ +#usda 1.0 +( + defaultPrim = "pSphere1" + endTimeCode = 3 + startTimeCode = 1 + upAxis = "Y" +) + +def Mesh "pSphere1" ( + kind = "component" +) +{ + uniform bool doubleSided = 1 + float3[] extent = [(-1.0000002, -1, -1.0000005), (1, 1, 1.0000001)] + int[] faceVertexCounts = [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3] + int[] faceVertexIndices = [0, 1, 21, 20, 1, 2, 22, 21, 2, 3, 23, 22, 3, 4, 24, 23, 4, 5, 25, 24, 5, 6, 26, 25, 6, 7, 27, 26, 7, 8, 28, 27, 8, 9, 29, 28, 9, 10, 30, 29, 10, 11, 31, 30, 11, 12, 32, 31, 12, 13, 33, 32, 13, 14, 34, 33, 14, 15, 35, 34, 15, 16, 36, 35, 16, 17, 37, 36, 17, 18, 38, 37, 18, 19, 39, 38, 19, 0, 20, 39, 20, 21, 41, 40, 21, 22, 42, 41, 22, 23, 43, 42, 23, 24, 44, 43, 24, 25, 45, 44, 25, 26, 46, 45, 26, 27, 47, 46, 27, 28, 48, 47, 28, 29, 49, 48, 29, 30, 50, 49, 30, 31, 51, 50, 31, 32, 52, 51, 32, 33, 53, 52, 33, 34, 54, 53, 34, 35, 55, 54, 35, 36, 56, 55, 36, 37, 57, 56, 37, 38, 58, 57, 38, 39, 59, 58, 39, 20, 40, 59, 40, 41, 61, 60, 41, 42, 62, 61, 42, 43, 63, 62, 43, 44, 64, 63, 44, 45, 65, 64, 45, 46, 66, 65, 46, 47, 67, 66, 47, 48, 68, 67, 48, 49, 69, 68, 49, 50, 70, 69, 50, 51, 71, 70, 51, 52, 72, 71, 52, 53, 73, 72, 53, 54, 74, 73, 54, 55, 75, 74, 55, 56, 76, 75, 56, 57, 77, 76, 57, 58, 78, 77, 58, 59, 79, 78, 59, 40, 60, 79, 60, 61, 81, 80, 61, 62, 82, 81, 62, 63, 83, 82, 63, 64, 84, 83, 64, 65, 85, 84, 65, 66, 86, 85, 66, 67, 87, 86, 67, 68, 88, 87, 68, 69, 89, 88, 69, 70, 90, 89, 70, 71, 91, 90, 71, 72, 92, 91, 72, 73, 93, 92, 73, 74, 94, 93, 74, 75, 95, 94, 75, 76, 96, 95, 76, 77, 97, 96, 77, 78, 98, 97, 78, 79, 99, 98, 79, 60, 80, 99, 80, 81, 101, 100, 81, 82, 102, 101, 82, 83, 103, 102, 83, 84, 104, 103, 84, 85, 105, 104, 85, 86, 106, 105, 86, 87, 107, 106, 87, 88, 108, 107, 88, 89, 109, 108, 89, 90, 110, 109, 90, 91, 111, 110, 91, 92, 112, 111, 92, 93, 113, 112, 93, 94, 114, 113, 94, 95, 115, 114, 95, 96, 116, 115, 96, 97, 117, 116, 97, 98, 118, 117, 98, 99, 119, 118, 99, 80, 100, 119, 100, 101, 121, 120, 101, 102, 122, 121, 102, 103, 123, 122, 103, 104, 124, 123, 104, 105, 125, 124, 105, 106, 126, 125, 106, 107, 127, 126, 107, 108, 128, 127, 108, 109, 129, 128, 109, 110, 130, 129, 110, 111, 131, 130, 111, 112, 132, 131, 112, 113, 133, 132, 113, 114, 134, 133, 114, 115, 135, 134, 115, 116, 136, 135, 116, 117, 137, 136, 117, 118, 138, 137, 118, 119, 139, 138, 119, 100, 120, 139, 120, 121, 141, 140, 121, 122, 142, 141, 122, 123, 143, 142, 123, 124, 144, 143, 124, 125, 145, 144, 125, 126, 146, 145, 126, 127, 147, 146, 127, 128, 148, 147, 128, 129, 149, 148, 129, 130, 150, 149, 130, 131, 151, 150, 131, 132, 152, 151, 132, 133, 153, 152, 133, 134, 154, 153, 134, 135, 155, 154, 135, 136, 156, 155, 136, 137, 157, 156, 137, 138, 158, 157, 138, 139, 159, 158, 139, 120, 140, 159, 140, 141, 161, 160, 141, 142, 162, 161, 142, 143, 163, 162, 143, 144, 164, 163, 144, 145, 165, 164, 145, 146, 166, 165, 146, 147, 167, 166, 147, 148, 168, 167, 148, 149, 169, 168, 149, 150, 170, 169, 150, 151, 171, 170, 151, 152, 172, 171, 152, 153, 173, 172, 153, 154, 174, 173, 154, 155, 175, 174, 155, 156, 176, 175, 156, 157, 177, 176, 157, 158, 178, 177, 158, 159, 179, 178, 159, 140, 160, 179, 160, 161, 181, 180, 161, 162, 182, 181, 162, 163, 183, 182, 163, 164, 184, 183, 164, 165, 185, 184, 165, 166, 186, 185, 166, 167, 187, 186, 167, 168, 188, 187, 168, 169, 189, 188, 169, 170, 190, 189, 170, 171, 191, 190, 171, 172, 192, 191, 172, 173, 193, 192, 173, 174, 194, 193, 174, 175, 195, 194, 175, 176, 196, 195, 176, 177, 197, 196, 177, 178, 198, 197, 178, 179, 199, 198, 179, 160, 180, 199, 180, 181, 201, 200, 181, 182, 202, 201, 182, 183, 203, 202, 183, 184, 204, 203, 184, 185, 205, 204, 185, 186, 206, 205, 186, 187, 207, 206, 187, 188, 208, 207, 188, 189, 209, 208, 189, 190, 210, 209, 190, 191, 211, 210, 191, 192, 212, 211, 192, 193, 213, 212, 193, 194, 214, 213, 194, 195, 215, 214, 195, 196, 216, 215, 196, 197, 217, 216, 197, 198, 218, 217, 198, 199, 219, 218, 199, 180, 200, 219, 200, 201, 221, 220, 201, 202, 222, 221, 202, 203, 223, 222, 203, 204, 224, 223, 204, 205, 225, 224, 205, 206, 226, 225, 206, 207, 227, 226, 207, 208, 228, 227, 208, 209, 229, 228, 209, 210, 230, 229, 210, 211, 231, 230, 211, 212, 232, 231, 212, 213, 233, 232, 213, 214, 234, 233, 214, 215, 235, 234, 215, 216, 236, 235, 216, 217, 237, 236, 217, 218, 238, 237, 218, 219, 239, 238, 219, 200, 220, 239, 220, 221, 241, 240, 221, 222, 242, 241, 222, 223, 243, 242, 223, 224, 244, 243, 224, 225, 245, 244, 225, 226, 246, 245, 226, 227, 247, 246, 227, 228, 248, 247, 228, 229, 249, 248, 229, 230, 250, 249, 230, 231, 251, 250, 231, 232, 252, 251, 232, 233, 253, 252, 233, 234, 254, 253, 234, 235, 255, 254, 235, 236, 256, 255, 236, 237, 257, 256, 237, 238, 258, 257, 238, 239, 259, 258, 239, 220, 240, 259, 240, 241, 261, 260, 241, 242, 262, 261, 242, 243, 263, 262, 243, 244, 264, 263, 244, 245, 265, 264, 245, 246, 266, 265, 246, 247, 267, 266, 247, 248, 268, 267, 248, 249, 269, 268, 249, 250, 270, 269, 250, 251, 271, 270, 251, 252, 272, 271, 252, 253, 273, 272, 253, 254, 274, 273, 254, 255, 275, 274, 255, 256, 276, 275, 256, 257, 277, 276, 257, 258, 278, 277, 258, 259, 279, 278, 259, 240, 260, 279, 260, 261, 281, 280, 261, 262, 282, 281, 262, 263, 283, 282, 263, 264, 284, 283, 264, 265, 285, 284, 265, 266, 286, 285, 266, 267, 287, 286, 267, 268, 288, 287, 268, 269, 289, 288, 269, 270, 290, 289, 270, 271, 291, 290, 271, 272, 292, 291, 272, 273, 293, 292, 273, 274, 294, 293, 274, 275, 295, 294, 275, 276, 296, 295, 276, 277, 297, 296, 277, 278, 298, 297, 278, 279, 299, 298, 279, 260, 280, 299, 280, 281, 301, 300, 281, 282, 302, 301, 282, 283, 303, 302, 283, 284, 304, 303, 284, 285, 305, 304, 285, 286, 306, 305, 286, 287, 307, 306, 287, 288, 308, 307, 288, 289, 309, 308, 289, 290, 310, 309, 290, 291, 311, 310, 291, 292, 312, 311, 292, 293, 313, 312, 293, 294, 314, 313, 294, 295, 315, 314, 295, 296, 316, 315, 296, 297, 317, 316, 297, 298, 318, 317, 298, 299, 319, 318, 299, 280, 300, 319, 300, 301, 321, 320, 301, 302, 322, 321, 302, 303, 323, 322, 303, 304, 324, 323, 304, 305, 325, 324, 305, 306, 326, 325, 306, 307, 327, 326, 307, 308, 328, 327, 308, 309, 329, 328, 309, 310, 330, 329, 310, 311, 331, 330, 311, 312, 332, 331, 312, 313, 333, 332, 313, 314, 334, 333, 314, 315, 335, 334, 315, 316, 336, 335, 316, 317, 337, 336, 317, 318, 338, 337, 318, 319, 339, 338, 319, 300, 320, 339, 320, 321, 341, 340, 321, 322, 342, 341, 322, 323, 343, 342, 323, 324, 344, 343, 324, 325, 345, 344, 325, 326, 346, 345, 326, 327, 347, 346, 327, 328, 348, 347, 328, 329, 349, 348, 329, 330, 350, 349, 330, 331, 351, 350, 331, 332, 352, 351, 332, 333, 353, 352, 333, 334, 354, 353, 334, 335, 355, 354, 335, 336, 356, 355, 336, 337, 357, 356, 337, 338, 358, 357, 338, 339, 359, 358, 339, 320, 340, 359, 340, 341, 361, 360, 341, 342, 362, 361, 342, 343, 363, 362, 343, 344, 364, 363, 344, 345, 365, 364, 345, 346, 366, 365, 346, 347, 367, 366, 347, 348, 368, 367, 348, 349, 369, 368, 349, 350, 370, 369, 350, 351, 371, 370, 351, 352, 372, 371, 352, 353, 373, 372, 353, 354, 374, 373, 354, 355, 375, 374, 355, 356, 376, 375, 356, 357, 377, 376, 357, 358, 378, 377, 358, 359, 379, 378, 359, 340, 360, 379, 1, 0, 380, 2, 1, 380, 3, 2, 380, 4, 3, 380, 5, 4, 380, 6, 5, 380, 7, 6, 380, 8, 7, 380, 9, 8, 380, 10, 9, 380, 11, 10, 380, 12, 11, 380, 13, 12, 380, 14, 13, 380, 15, 14, 380, 16, 15, 380, 17, 16, 380, 18, 17, 380, 19, 18, 380, 0, 19, 380, 360, 361, 381, 361, 362, 381, 362, 363, 381, 363, 364, 381, 364, 365, 381, 365, 366, 381, 366, 367, 381, 367, 368, 381, 368, 369, 381, 369, 370, 381, 370, 371, 381, 371, 372, 381, 372, 373, 381, 373, 374, 381, 374, 375, 381, 375, 376, 381, 376, 377, 381, 377, 378, 381, 378, 379, 381, 379, 360, 381] + rel material:binding = + point3f[] points = [(0.14877813, -0.98768836, -0.048340943), (0.12655823, -0.98768836, -0.09194993), (0.09194993, -0.98768836, -0.12655823), (0.048340935, -0.98768836, -0.14877811), (0, -0.98768836, -0.15643455), (-0.048340935, -0.98768836, -0.1487781), (-0.09194992, -0.98768836, -0.1265582), (-0.12655818, -0.98768836, -0.0919499), (-0.14877807, -0.98768836, -0.048340924), (-0.15643452, -0.98768836, 0), (-0.14877807, -0.98768836, 0.048340924), (-0.12655818, -0.98768836, 0.091949895), (-0.091949895, -0.98768836, 0.12655817), (-0.048340924, -0.98768836, 0.14877805), (-4.6621107e-9, -0.98768836, 0.15643449), (0.04834091, -0.98768836, 0.14877804), (0.09194988, -0.98768836, 0.12655815), (0.12655815, -0.98768836, 0.09194989), (0.14877804, -0.98768836, 0.048340913), (0.15643448, -0.98768836, 0), (0.29389283, -0.95105654, -0.095491566), (0.25000018, -0.95105654, -0.18163574), (0.18163574, -0.95105654, -0.25000015), (0.09549155, -0.95105654, -0.2938928), (0, -0.95105654, -0.30901715), (-0.09549155, -0.95105654, -0.29389277), (-0.18163571, -0.95105654, -0.2500001), (-0.2500001, -0.95105654, -0.1816357), (-0.2938927, -0.95105654, -0.09549153), (-0.30901706, -0.95105654, 0), (-0.2938927, -0.95105654, 0.09549153), (-0.25000006, -0.95105654, 0.18163568), (-0.18163568, -0.95105654, 0.25000006), (-0.09549153, -0.95105654, 0.29389268), (-9.209424e-9, -0.95105654, 0.30901703), (0.0954915, -0.95105654, 0.29389265), (0.18163563, -0.95105654, 0.25000003), (0.25, -0.95105654, 0.18163565), (0.29389265, -0.95105654, 0.095491506), (0.309017, -0.95105654, 0), (0.43177092, -0.8910065, -0.14029087), (0.3672863, -0.8910065, -0.2668491), (0.2668491, -0.8910065, -0.36728626), (0.14029086, -0.8910065, -0.43177086), (0, -0.8910065, -0.45399073), (-0.14029086, -0.8910065, -0.43177083), (-0.26684904, -0.8910065, -0.36728618), (-0.36728615, -0.8910065, -0.266849), (-0.43177077, -0.8910065, -0.14029081), (-0.45399064, -0.8910065, 0), (-0.43177077, -0.8910065, 0.14029081), (-0.36728612, -0.8910065, 0.26684898), (-0.26684898, -0.8910065, 0.36728612), (-0.14029081, -0.8910065, 0.4317707), (-1.3529972e-8, -0.8910065, 0.45399058), (0.14029078, -0.8910065, 0.43177068), (0.26684892, -0.8910065, 0.3672861), (0.36728606, -0.8910065, 0.26684895), (0.43177065, -0.8910065, 0.1402908), (0.45399052, -0.8910065, 0), (0.55901736, -0.809017, -0.18163574), (0.47552857, -0.809017, -0.3454917), (0.3454917, -0.809017, -0.47552854), (0.18163572, -0.809017, -0.5590173), (0, -0.809017, -0.58778554), (-0.18163572, -0.809017, -0.55901724), (-0.34549165, -0.809017, -0.47552842), (-0.4755284, -0.809017, -0.3454916), (-0.5590171, -0.809017, -0.18163566), (-0.58778536, -0.809017, 0), (-0.5590171, -0.809017, 0.18163566), (-0.47552836, -0.809017, 0.34549156), (-0.34549156, -0.809017, 0.47552833), (-0.18163566, -0.809017, 0.55901706), (-1.7517365e-8, -0.809017, 0.5877853), (0.18163562, -0.809017, 0.55901706), (0.3454915, -0.809017, 0.4755283), (0.47552827, -0.809017, 0.34549153), (0.559017, -0.809017, 0.18163563), (0.58778524, -0.809017, 0), (0.67249894, -0.70710677, -0.21850814), (0.5720618, -0.70710677, -0.41562718), (0.41562718, -0.70710677, -0.5720617), (0.21850812, -0.70710677, -0.6724989), (0, -0.70710677, -0.7071071), (-0.21850812, -0.70710677, -0.6724988), (-0.4156271, -0.70710677, -0.5720616), (-0.57206154, -0.70710677, -0.41562706), (-0.6724987, -0.70710677, -0.21850805), (-0.70710695, -0.70710677, 0), (-0.6724987, -0.70710677, 0.21850805), (-0.57206154, -0.70710677, 0.415627), (-0.415627, -0.70710677, 0.5720615), (-0.21850805, -0.70710677, 0.6724986), (-2.1073424e-8, -0.70710677, 0.7071068), (0.21850799, -0.70710677, 0.6724986), (0.4156269, -0.70710677, 0.5720614), (0.5720614, -0.70710677, 0.41562697), (0.6724985, -0.70710677, 0.21850802), (0.70710677, -0.70710677, 0), (0.7694214, -0.58778524, -0.25000015), (0.65450895, -0.58778524, -0.47552854), (0.47552854, -0.58778524, -0.6545089), (0.25000012, -0.58778524, -0.7694213), (0, -0.58778524, -0.80901736), (-0.25000012, -0.58778524, -0.7694212), (-0.47552845, -0.58778524, -0.65450877), (-0.6545087, -0.58778524, -0.4755284), (-0.7694211, -0.58778524, -0.25000006), (-0.8090172, -0.58778524, 0), (-0.7694211, -0.58778524, 0.25000006), (-0.65450865, -0.58778524, 0.47552836), (-0.47552836, -0.58778524, 0.6545086), (-0.25000006, -0.58778524, 0.769421), (-2.4110586e-8, -0.58778524, 0.8090171), (0.24999999, -0.58778524, 0.769421), (0.47552827, -0.58778524, 0.65450853), (0.65450853, -0.58778524, 0.4755283), (0.7694209, -0.58778524, 0.25), (0.809017, -0.58778524, 0), (0.8473981, -0.45399052, -0.27533633), (0.7208399, -0.45399052, -0.5237208), (0.5237208, -0.45399052, -0.72083986), (0.2753363, -0.45399052, -0.847398), (0, -0.45399052, -0.89100695), (-0.2753363, -0.45399052, -0.847398), (-0.5237207, -0.45399052, -0.7208397), (-0.7208396, -0.45399052, -0.5237206), (-0.8473978, -0.45399052, -0.2753362), (-0.89100677, -0.45399052, 0), (-0.8473978, -0.45399052, 0.2753362), (-0.7208396, -0.45399052, 0.5237206), (-0.5237206, -0.45399052, 0.72083956), (-0.2753362, -0.45399052, 0.8473977), (-2.6554064e-8, -0.45399052, 0.89100665), (0.27533615, -0.45399052, 0.8473976), (0.5237205, -0.45399052, 0.7208395), (0.72083944, -0.45399052, 0.52372056), (0.84739757, -0.45399052, 0.27533618), (0.8910065, -0.45399052, 0), (0.9045091, -0.30901697, -0.2938928), (0.7694214, -0.30901697, -0.55901736), (0.55901736, -0.30901697, -0.76942134), (0.29389277, -0.30901697, -0.904509), (0, -0.30901697, -0.951057), (-0.29389277, -0.30901697, -0.90450895), (-0.55901724, -0.30901697, -0.7694212), (-0.76942116, -0.30901697, -0.5590172), (-0.90450877, -0.30901697, -0.2938927), (-0.9510568, -0.30901697, 0), (-0.90450877, -0.30901697, 0.2938927), (-0.7694211, -0.30901697, 0.5590171), (-0.5590171, -0.30901697, 0.76942104), (-0.2938927, -0.30901697, 0.90450865), (-2.8343694e-8, -0.30901697, 0.95105666), (0.29389262, -0.30901697, 0.9045086), (0.559017, -0.30901697, 0.769421), (0.7694209, -0.30901697, 0.55901706), (0.90450853, -0.30901697, 0.29389265), (0.95105654, -0.30901697, 0), (0.93934804, -0.15643437, -0.30521268), (0.7990572, -0.15643437, -0.580549), (0.580549, -0.15643437, -0.7990571), (0.30521265, -0.15643437, -0.9393479), (0, -0.15643437, -0.98768884), (-0.30521265, -0.15643437, -0.93934786), (-0.5805489, -0.15643437, -0.79905695), (-0.7990569, -0.15643437, -0.5805488), (-0.9393477, -0.15643437, -0.30521256), (-0.9876886, -0.15643437, 0), (-0.9393477, -0.15643437, 0.30521256), (-0.7990568, -0.15643437, 0.58054876), (-0.58054876, -0.15643437, 0.79905677), (-0.30521256, -0.15643437, 0.93934757), (-2.9435407e-8, -0.15643437, 0.9876885), (0.30521247, -0.15643437, 0.93934757), (0.58054864, -0.15643437, 0.7990567), (0.79905665, -0.15643437, 0.5805487), (0.9393475, -0.15643437, 0.3052125), (0.98768836, -0.15643437, 0), (0.95105714, 0, -0.30901718), (0.80901754, 0, -0.5877856), (0.5877856, 0, -0.8090175), (0.30901715, 0, -0.951057), (0, 0, -1.0000005), (-0.30901715, 0, -0.95105696), (-0.5877855, 0, -0.8090173), (-0.80901724, 0, -0.5877854), (-0.9510568, 0, -0.30901706), (-1.0000002, 0, 0), (-0.9510568, 0, 0.30901706), (-0.8090172, 0, 0.58778536), (-0.58778536, 0, 0.8090171), (-0.30901706, 0, 0.95105666), (-2.9802322e-8, 0, 1.0000001), (0.30901697, 0, 0.9510566), (0.58778524, 0, 0.80901706), (0.809017, 0, 0.5877853), (0.95105654, 0, 0.309017), (1, 0, 0), (0.93934804, 0.15643437, -0.30521268), (0.7990572, 0.15643437, -0.580549), (0.580549, 0.15643437, -0.7990571), (0.30521265, 0.15643437, -0.9393479), (0, 0.15643437, -0.98768884), (-0.30521265, 0.15643437, -0.93934786), (-0.5805489, 0.15643437, -0.79905695), (-0.7990569, 0.15643437, -0.5805488), (-0.9393477, 0.15643437, -0.30521256), (-0.9876886, 0.15643437, 0), (-0.9393477, 0.15643437, 0.30521256), (-0.7990568, 0.15643437, 0.58054876), (-0.58054876, 0.15643437, 0.79905677), (-0.30521256, 0.15643437, 0.93934757), (-2.9435407e-8, 0.15643437, 0.9876885), (0.30521247, 0.15643437, 0.93934757), (0.58054864, 0.15643437, 0.7990567), (0.79905665, 0.15643437, 0.5805487), (0.9393475, 0.15643437, 0.3052125), (0.98768836, 0.15643437, 0), (0.9045091, 0.30901697, -0.2938928), (0.7694214, 0.30901697, -0.55901736), (0.55901736, 0.30901697, -0.76942134), (0.29389277, 0.30901697, -0.904509), (0, 0.30901697, -0.951057), (-0.29389277, 0.30901697, -0.90450895), (-0.55901724, 0.30901697, -0.7694212), (-0.76942116, 0.30901697, -0.5590172), (-0.90450877, 0.30901697, -0.2938927), (-0.9510568, 0.30901697, 0), (-0.90450877, 0.30901697, 0.2938927), (-0.7694211, 0.30901697, 0.5590171), (-0.5590171, 0.30901697, 0.76942104), (-0.2938927, 0.30901697, 0.90450865), (-2.8343694e-8, 0.30901697, 0.95105666), (0.29389262, 0.30901697, 0.9045086), (0.559017, 0.30901697, 0.769421), (0.7694209, 0.30901697, 0.55901706), (0.90450853, 0.30901697, 0.29389265), (0.95105654, 0.30901697, 0), (0.8473981, 0.45399052, -0.27533633), (0.7208399, 0.45399052, -0.5237208), (0.5237208, 0.45399052, -0.72083986), (0.2753363, 0.45399052, -0.847398), (0, 0.45399052, -0.89100695), (-0.2753363, 0.45399052, -0.847398), (-0.5237207, 0.45399052, -0.7208397), (-0.7208396, 0.45399052, -0.5237206), (-0.8473978, 0.45399052, -0.2753362), (-0.89100677, 0.45399052, 0), (-0.8473978, 0.45399052, 0.2753362), (-0.7208396, 0.45399052, 0.5237206), (-0.5237206, 0.45399052, 0.72083956), (-0.2753362, 0.45399052, 0.8473977), (-2.6554064e-8, 0.45399052, 0.89100665), (0.27533615, 0.45399052, 0.8473976), (0.5237205, 0.45399052, 0.7208395), (0.72083944, 0.45399052, 0.52372056), (0.84739757, 0.45399052, 0.27533618), (0.8910065, 0.45399052, 0), (0.7694214, 0.58778524, -0.25000015), (0.65450895, 0.58778524, -0.47552854), (0.47552854, 0.58778524, -0.6545089), (0.25000012, 0.58778524, -0.7694213), (0, 0.58778524, -0.80901736), (-0.25000012, 0.58778524, -0.7694212), (-0.47552845, 0.58778524, -0.65450877), (-0.6545087, 0.58778524, -0.4755284), (-0.7694211, 0.58778524, -0.25000006), (-0.8090172, 0.58778524, 0), (-0.7694211, 0.58778524, 0.25000006), (-0.65450865, 0.58778524, 0.47552836), (-0.47552836, 0.58778524, 0.6545086), (-0.25000006, 0.58778524, 0.769421), (-2.4110586e-8, 0.58778524, 0.8090171), (0.24999999, 0.58778524, 0.769421), (0.47552827, 0.58778524, 0.65450853), (0.65450853, 0.58778524, 0.4755283), (0.7694209, 0.58778524, 0.25), (0.809017, 0.58778524, 0), (0.67249894, 0.70710677, -0.21850814), (0.5720618, 0.70710677, -0.41562718), (0.41562718, 0.70710677, -0.5720617), (0.21850812, 0.70710677, -0.6724989), (0, 0.70710677, -0.7071071), (-0.21850812, 0.70710677, -0.6724988), (-0.4156271, 0.70710677, -0.5720616), (-0.57206154, 0.70710677, -0.41562706), (-0.6724987, 0.70710677, -0.21850805), (-0.70710695, 0.70710677, 0), (-0.6724987, 0.70710677, 0.21850805), (-0.57206154, 0.70710677, 0.415627), (-0.415627, 0.70710677, 0.5720615), (-0.21850805, 0.70710677, 0.6724986), (-2.1073424e-8, 0.70710677, 0.7071068), (0.21850799, 0.70710677, 0.6724986), (0.4156269, 0.70710677, 0.5720614), (0.5720614, 0.70710677, 0.41562697), (0.6724985, 0.70710677, 0.21850802), (0.70710677, 0.70710677, 0), (0.55901736, 0.809017, -0.18163574), (0.47552857, 0.809017, -0.3454917), (0.3454917, 0.809017, -0.47552854), (0.18163572, 0.809017, -0.5590173), (0, 0.809017, -0.58778554), (-0.18163572, 0.809017, -0.55901724), (-0.34549165, 0.809017, -0.47552842), (-0.4755284, 0.809017, -0.3454916), (-0.5590171, 0.809017, -0.18163566), (-0.58778536, 0.809017, 0), (-0.5590171, 0.809017, 0.18163566), (-0.47552836, 0.809017, 0.34549156), (-0.34549156, 0.809017, 0.47552833), (-0.18163566, 0.809017, 0.55901706), (-1.7517365e-8, 0.809017, 0.5877853), (0.18163562, 0.809017, 0.55901706), (0.3454915, 0.809017, 0.4755283), (0.47552827, 0.809017, 0.34549153), (0.559017, 0.809017, 0.18163563), (0.58778524, 0.809017, 0), (0.43177092, 0.8910065, -0.14029087), (0.3672863, 0.8910065, -0.2668491), (0.2668491, 0.8910065, -0.36728626), (0.14029086, 0.8910065, -0.43177086), (0, 0.8910065, -0.45399073), (-0.14029086, 0.8910065, -0.43177083), (-0.26684904, 0.8910065, -0.36728618), (-0.36728615, 0.8910065, -0.266849), (-0.43177077, 0.8910065, -0.14029081), (-0.45399064, 0.8910065, 0), (-0.43177077, 0.8910065, 0.14029081), (-0.36728612, 0.8910065, 0.26684898), (-0.26684898, 0.8910065, 0.36728612), (-0.14029081, 0.8910065, 0.4317707), (-1.3529972e-8, 0.8910065, 0.45399058), (0.14029078, 0.8910065, 0.43177068), (0.26684892, 0.8910065, 0.3672861), (0.36728606, 0.8910065, 0.26684895), (0.43177065, 0.8910065, 0.1402908), (0.45399052, 0.8910065, 0), (0.29389283, 0.95105654, -0.095491566), (0.25000018, 0.95105654, -0.18163574), (0.18163574, 0.95105654, -0.25000015), (0.09549155, 0.95105654, -0.2938928), (0, 0.95105654, -0.30901715), (-0.09549155, 0.95105654, -0.29389277), (-0.18163571, 0.95105654, -0.2500001), (-0.2500001, 0.95105654, -0.1816357), (-0.2938927, 0.95105654, -0.09549153), (-0.30901706, 0.95105654, 0), (-0.2938927, 0.95105654, 0.09549153), (-0.25000006, 0.95105654, 0.18163568), (-0.18163568, 0.95105654, 0.25000006), (-0.09549153, 0.95105654, 0.29389268), (-9.209424e-9, 0.95105654, 0.30901703), (0.0954915, 0.95105654, 0.29389265), (0.18163563, 0.95105654, 0.25000003), (0.25, 0.95105654, 0.18163565), (0.29389265, 0.95105654, 0.095491506), (0.309017, 0.95105654, 0), (0.14877813, 0.98768836, -0.048340943), (0.12655823, 0.98768836, -0.09194993), (0.09194993, 0.98768836, -0.12655823), (0.048340935, 0.98768836, -0.14877811), (0, 0.98768836, -0.15643455), (-0.048340935, 0.98768836, -0.1487781), (-0.09194992, 0.98768836, -0.1265582), (-0.12655818, 0.98768836, -0.0919499), (-0.14877807, 0.98768836, -0.048340924), (-0.15643452, 0.98768836, 0), (-0.14877807, 0.98768836, 0.048340924), (-0.12655818, 0.98768836, 0.091949895), (-0.091949895, 0.98768836, 0.12655817), (-0.048340924, 0.98768836, 0.14877805), (-4.6621107e-9, 0.98768836, 0.15643449), (0.04834091, 0.98768836, 0.14877804), (0.09194988, 0.98768836, 0.12655815), (0.12655815, 0.98768836, 0.09194989), (0.14877804, 0.98768836, 0.048340913), (0.15643448, 0.98768836, 0), (0, -1, 0), (0, 1, 0)] + color3f[] primvars:displayColor = [(0.13320851, 0.13320851, 0.13320851)] ( + customData = { + dictionary Maya = { + bool generated = 1 + } + } + ) + double3 xformOp:translate.timeSamples = { + 1: (-3.155580187855774, 0, 0), + 2: (0.48378179248051545, 0, 0), + 3: (4.123143772816806, 0, 0), + } + uniform token[] xformOpOrder = ["xformOp:translate"] + + def Scope "Looks" + { + def Material "initialShadingGroup" + { + color3f inputs:displayColor = (0.13320851, 0.13320851, 0.13320851) + float inputs:displayOpacity + color3f inputs:transparency + token outputs:ri:surface.connect = + + def Shader "initialShadingGroup_lambert" + { + uniform token info:id = "PxrDiffuse" + color3f inputs:diffuseColor.connect = + color3f inputs:transmissionColor.connect = + token outputs:out + } + } + } +} + diff --git a/testsuite/test_0018/data/test.ass b/testsuite/test_0018/data/test.ass new file mode 100755 index 0000000000..12f0df36b4 --- /dev/null +++ b/testsuite/test_0018/data/test.ass @@ -0,0 +1,104 @@ +### exported: Mon Dec 17 21:54:24 2018 +### from: Arnold 5.2.2.0 [30b8ba14] windows icc-17.0.2 oiio-2.0.1 osl-1.10.1 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 2018/12/04 22:02:04 +### host app: MtoA 3.1.3.wip 7d48f6c4 (develop) Maya 2018 +### bounds: -1 -8.268288 -1 1 -6.268287 1 +### user: blaines +### render_layer: defaultRenderLayer +### scene: D:/arnold/scenes/usd.ma + + + +options +{ + AA_samples 3 + outputs "RGBA RGBA myfilter mydriver" + xres 160 + yres 120 + pixel_aspect_ratio 1.33333325 + camera "perspShape" + frame 1 +} + +gaussian_filter +{ + name myfilter +} + +driver_tiff +{ + name mydriver + filename "testrender.tif" + color_space "sRGB" +} + +persp_camera +{ + name perspShape + matrix + 0.716910601 2.77555756e-17 -0.697165132 0 + -0.320169091 0.888310015 -0.329237103 0 + 0.619298756 0.459244281 0.636838853 0 + 6.41154099 -5.45881033 2.70130825 1 + + near_clip 0.100000001 + far_clip 10000 + screen_window_min -1 -1 + screen_window_max 1 1 + shutter_start 0 + shutter_end 1 + shutter_type "box" + rolling_shutter "off" + rolling_shutter_duration 0 + motion_start 0 + motion_end 1 + exposure 0 + fov 80 + uv_remap 0 0 0 1 + declare maya_full_name constant STRING + maya_full_name "|persp|perspShape" +} + +distant_light +{ + name directionalLightShape1 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 0 0 1 + exposure 0 + cast_shadows on + cast_volumetric_shadows on + shadow_density 1 + samples 1 + normalize on + diffuse 1 + specular 1 + sss 1 + indirect 1 + max_bounces 999 + volume_samples 2 + volume 1 + aov "default" + angle 0 + declare maya_full_name constant STRING + maya_full_name "|directionalLight1|directionalLightShape1" +} + +usd +{ + name aiUsdShape2 + visibility 255 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 -7.26828718 0 1 + use_light_group off + override_nodes off + filename "sphere.usd" + frame 2 + declare maya_full_name constant STRING + maya_full_name "|aiUsd2|aiUsdShape2" +} + diff --git a/testsuite/test_0018/ref/reference.log b/testsuite/test_0018/ref/reference.log new file mode 100755 index 0000000000..f325f09aef --- /dev/null +++ b/testsuite/test_0018/ref/reference.log @@ -0,0 +1,208 @@ +00:00:00 58MB | log started Mon Jun 17 20:18:18 2019 +00:00:00 58MB | Arnold 5.4.0.0 [6ce40857] windows icc-17.0.2 oiio-2.1.0 osl-1.11.0 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 optix-6.0.0 2019/06/13 15:06:18 +00:00:00 58MB | running on REM8WCK8D2, pid=15904 +00:00:00 58MB | 2 x Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz (20 cores, 40 logical) with 65456MB +00:00:00 58MB | NVIDIA driver version 430.64 (Optix 60100) +00:00:00 58MB | GPU 0: GeForce RTX 2080 Ti @ 1635MHz (compute 7.5) with 11264MB (10990MB available) (NVLink:0) +00:00:00 58MB | GPU 1: Quadro K620 @ 1124MHz (compute 5.0) with 2048MB (1449MB available) (NVLink:0) +00:00:00 58MB | Windows 7 Enterprise Edition Service Pack 1 (version 6.1, build 7601) +00:00:00 58MB | soft limit for open files raised from 512 to 2048 +00:00:00 58MB | +00:00:00 58MB | loading plugins from D:\arnold\usd_procedural\build\windows_x86_64\msvc_opt\usd-0.19.5_arnold-5.4.0.0\procedural ... +00:00:00 58MB | usd_proc.dll: usd uses Arnold 5.4.0.0 +00:00:00 58MB | loaded 1 plugins from 1 lib(s) in 0:00.07 +00:00:00 58MB | loading plugins from D:\arnold\releases\Arnold_latest-windows\bin\..\plugins ... +00:00:00 58MB | alembic_proc.dll: alembic uses Arnold 5.4.0.0 +00:00:00 58MB | cryptomatte.dll: cryptomatte uses Arnold 5.4.0.0 +00:00:00 58MB | cryptomatte.dll: cryptomatte_filter uses Arnold 5.4.0.0 +00:00:00 58MB | cryptomatte.dll: cryptomatte_manifest_driver uses Arnold 5.4.0.0 +00:00:00 58MB | usd_proc.dll: usd uses Arnold 5.4.0.0 +00:00:00 58MB WARNING | node "usd" is already installed +00:00:00 58MB | loaded 5 plugins from 3 lib(s) in 0:00.00 +00:00:00 58MB | [kick] command: D:\arnold\releases\Arnold_latest-windows\bin\kick test.ass -dw -r 160 120 -bs 16 -o testrender.tif -set driver_tiff.dither false -nocrashpopup -dp -v 6 +00:00:00 58MB | loading plugins from . ... +00:00:00 58MB | no plugins loaded +00:00:00 58MB | [metadata] loading metadata file: test.ass +00:00:00 59MB | [ass] loading test.ass ... +00:00:00 59MB | [ass] read 1925 bytes, 6 nodes in 0:00.00 +00:00:00 59MB | [kick] applying 1 attr value override +00:00:00 59MB | +00:00:00 59MB | authorizing with default license managers: rlm, clm ... +00:00:02 67MB | [clm-network] authorized for "86985ARNOL_2018_0F" in 0:02.86 +00:00:02 67MB | [clm-network] expiration date: permanent, in use: 1/1000 +00:00:02 67MB | +00:00:02 69MB | [color_manager] no color manager is active +00:00:02 69MB | [color_manager] rendering color space is "linear" with declared chromaticities: +00:00:02 69MB | r(0.6400, 0.3300) g(0.3000, 0.6000) b(0.1500, 0.0600) and w(0.3127, 0.3290) +00:00:02 80MB | +00:00:02 80MB | there are 1 light and 2 objects: +00:00:02 80MB | 1 persp_camera +00:00:02 80MB | 1 distant_light +00:00:02 80MB | 1 utility +00:00:02 80MB | 1 driver_tiff +00:00:02 80MB | 1 gaussian_filter +00:00:02 80MB | 1 list_aggregate +00:00:02 80MB | 1 usd +00:00:02 80MB | +00:00:02 80MB | rendering image at 160 x 120, 3 AA samples +00:00:02 80MB | AA samples max +00:00:02 80MB | AA sample clamp +00:00:02 80MB | diffuse +00:00:02 80MB | specular +00:00:02 80MB | transmission samples 2 / depth 2 +00:00:02 80MB | volume indirect +00:00:02 80MB | total depth 10 +00:00:02 80MB | bssrdf samples 2 +00:00:02 80MB | transparency depth 10 +00:00:02 80MB | initializing 8 nodes ... +00:00:03 91MB WARNING | ///////////////////////////// ?YES /pSphere1 +00:00:03 91MB WARNING | 2.000000 // 3.000000 +00:00:03 91MB WARNING | amount of keys = 0000000000000003 +00:00:03 91MB WARNING | for step 2.000000 we have matrix 1.000000 0.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.483782 0.000000 0.000000 1.000000 +00:00:03 91MB WARNING | for step 2.500000 we have matrix 1.000000 0.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 1.000000 0.000000 2.303463 0.000000 0.000000 1.000000 +00:00:03 91MB WARNING | for step 3.000000 we have matrix 1.000000 0.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 1.000000 0.000000 4.123144 0.000000 0.000000 1.000000 +00:00:03 91MB WARNING | 0000000000000003 +00:00:03 92MB | [proc] aiUsdShape2: loaded 1 nodes (1 objects, 0 shaders) +00:00:03 92MB | creating root object list ... +00:00:03 92MB | node initialization done in 0:00.07 (multithreaded) +00:00:03 92MB | updating 10 nodes ... +00:00:03 92MB | directionalLightShape1: distant_light using 1 sample, 2 volume samples +00:00:03 92MB | scene bounds: (-0.516218424 -8.26828766 -1.00000048) -> (5.12314367 -6.26828718 1.00000012) +00:00:03 92MB | node update done in 0:00.00 (multithreaded) +00:00:03 92MB | [aov] parsing 1 output statements ... +00:00:03 92MB | [aov] registered driver: "mydriver" (driver_tiff) +00:00:03 92MB | [aov] * "RGBA" of type RGBA filtered by "myfilter" (gaussian_filter) +00:00:03 92MB | [aov] done preparing 2 AOVs for 1 output to 1 driver (0 deep AOVs) +00:00:03 93MB | starting 40 bucket workers of size 16x16 ... +00:00:03 98MB | [subdiv] /pSphere1: regular subdivision done - 1 iterations: 400 faces => 1560 quads - 0:00.00 +00:00:03 99MB | [accel] polymesh bvh4 done - 0:00.00 (wall time) - 1560 prims, 1 key +00:00:03 100MB | 0% done - 115 rays/pixel +00:00:03 100MB | 5% done - 68 rays/pixel +00:00:03 100MB | 10% done - 7 rays/pixel +00:00:03 100MB | 15% done - 9 rays/pixel +00:00:03 100MB | 20% done - 11 rays/pixel +00:00:03 100MB | 25% done - 16 rays/pixel +00:00:03 100MB | 30% done - 10 rays/pixel +00:00:03 100MB | 35% done - 14 rays/pixel +00:00:03 100MB | 40% done - 3 rays/pixel +00:00:03 100MB | 45% done - 9 rays/pixel +00:00:03 100MB | 50% done - 5 rays/pixel +00:00:03 100MB | 55% done - 5 rays/pixel +00:00:03 100MB | 60% done - 13 rays/pixel +00:00:03 100MB | 65% done - 7 rays/pixel +00:00:03 101MB | 70% done - 6 rays/pixel +00:00:03 101MB | 75% done - 2 rays/pixel +00:00:03 101MB | 80% done - 0 rays/pixel +00:00:03 101MB | 85% done - 0 rays/pixel +00:00:03 101MB | 90% done - 0 rays/pixel +00:00:03 101MB | 95% done - 0 rays/pixel +00:00:03 101MB | 100% done - 0 rays/pixel +00:00:03 101MB | render done in 0:00.017 +00:00:03 101MB | [driver_tiff] writing file `testrender.tif' +00:00:03 101MB | render done +00:00:03 101MB | +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | scene creation time 0:00.30 machine utilization (0.25%) +00:00:03 101MB | plugin loading 0:00.07 +00:00:03 101MB | unaccounted 0:00.22 +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | frame time 0:02.99 machine utilization (1.62%) +00:00:03 101MB | node init 0:00.07 +00:00:03 101MB | rendering 0:00.01 +00:00:03 101MB | pixel rendering 0:00.01 +00:00:03 101MB | unaccounted 0:02.89 +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | top session self-times by category +00:00:03 101MB | InitializeNodes 0:00.05 (54.66%) +00:00:03 101MB | worker waiting 0:00.02 (26.07%) +00:00:03 101MB | thread blocked 0:00.00 ( 7.06%) +00:00:03 101MB | ray traversal+intersection 0:00.00 ( 2.86%) +00:00:03 101MB | Plugin loader 0:00.00 ( 2.03%) +00:00:03 101MB | node_init (aiUsdShape2) 0:00.00 ( 1.87%) +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | top session self-times by node +00:00:03 101MB | InitializeNodes 0:00.05 (54.66%) +00:00:03 101MB | worker waiting 0:00.02 (26.07%) +00:00:03 101MB | polymesh:/pSphere1 0:00.00 ( 4.48%) +00:00:03 101MB | thread blocked 0:00.00 ( 4.06%) +00:00:03 101MB | thread blocked 0:00.00 ( 2.99%) +00:00:03 101MB | ray traversal+intersection 0:00.00 ( 2.86%) +00:00:03 101MB | Plugin loader 0:00.00 ( 2.03%) +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | peak CPU memory used 101.36MB +00:00:03 101MB | at startup 36.86MB +00:00:03 101MB | plugins 4.94MB +00:00:03 101MB | AOV samples 6.52MB +00:00:03 101MB | output buffers 0.23MB +00:00:03 101MB | framebuffers 0.31MB +00:00:03 101MB | node overhead 0.00MB +00:00:03 101MB | message passing 0.08MB +00:00:03 101MB | memory pools 30.05MB +00:00:03 101MB | geometry 0.03MB +00:00:03 101MB | subdivs 0.03MB +00:00:03 101MB | accel. structs 0.05MB +00:00:03 101MB | strings 12.00MB +00:00:03 101MB | profiler 0.01MB +00:00:03 101MB | unaccounted 10.26MB +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | ray counts ( /pixel, /sample) (% total) (avg. hits) (max hits) +00:00:03 101MB | camera 192800 ( 10.04, 1.00) (100.00%) ( 0.08) ( 1) +00:00:03 101MB | total 192800 ( 10.04, 1.00) (100.00%) ( 0.08) ( 1) +00:00:03 101MB | by ray depth: 0 +00:00:03 101MB | total 100.0% +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | shader calls ( /pixel, /sample) (% total) +00:00:03 101MB | primary 16080 ( 0.84, 0.08) (100.00%) +00:00:03 101MB | total 16080 ( 0.84, 0.08) (100.00%) +00:00:03 101MB | by ray depth: 0 +00:00:03 101MB | total 100.0% +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | geometry (% hit ) (instances) ( init mem, final mem) +00:00:03 101MB | lists 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:03 101MB | procs 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:03 101MB | subdivs 1 (100.0%) ( 0) ( 0.01, 0.03) +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | geometric elements ( min) ( avg.) ( max) +00:00:03 101MB | objects (procs) 1 ( 1) ( 1.0) ( 1) +00:00:03 101MB | subdiv patches 400 ( 400) ( 400.0) ( 400) +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | triangle tessellation ( min) ( avg.) ( max) (/ element) (% total) +00:00:03 101MB | subdivs 3120 ( 3120) ( 3120.0) ( 3120) ( 7.80) (100.00%) +00:00:03 101MB | iterations 1 3120 ( 3120) ( 3120.0) ( 3120) ( 7.80) (100.00%) +00:00:03 101MB | unique triangles 3120 +00:00:03 101MB | visible triangles 6240 +00:00:03 101MB | CPU memory use 0.03MB +00:00:03 101MB | vertices 0.02MB +00:00:03 101MB | vertex indices 0.01MB +00:00:03 101MB | packed normals 0.01MB +00:00:03 101MB | normal indices 0.00MB +00:00:03 101MB | uniform indices 0.00MB +00:00:03 101MB | userdata 0.00MB +00:00:03 101MB | largest polymeshes by triangle count +00:00:03 101MB | 3120 tris -- /pSphere1 +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | acceleration structures: (% total) +00:00:03 101MB | list 2 ( 66.67%) +00:00:03 101MB | bvh 1 ( 33.33%) +00:00:03 101MB | total 3 (100.00%) +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | number of warnings, warning type: +00:00:03 101MB | 1: %f // %f +00:00:03 101MB | 1: %p +00:00:03 101MB | 1: ///////////////////////////// ?YES %s +00:00:03 101MB | 1: amount of keys = %p +00:00:03 101MB | 3: for step %f we have matrix %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f +00:00:03 101MB | 1: node "%s" is already installed +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | performance warnings: +00:00:03 101MB WARNING | Rendering CPU utilization was only 2%. Your render may be bound by a single threaded process or I/O. +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 96MB | +00:00:03 96MB | releasing resources +00:00:03 83MB | unloading 4 plugins +00:00:03 83MB | closing usd_proc.dll ... +00:00:03 82MB | closing alembic_proc.dll ... +00:00:03 82MB | closing cryptomatte.dll ... +00:00:03 82MB | closing usd_proc.dll ... +00:00:03 75MB | unloading plugins done +00:00:03 75MB | Arnold shutdown diff --git a/testsuite/test_0018/ref/reference.tif b/testsuite/test_0018/ref/reference.tif new file mode 100755 index 0000000000..d8bf9e2955 Binary files /dev/null and b/testsuite/test_0018/ref/reference.tif differ diff --git a/testsuite/test_0020/README b/testsuite/test_0020/README new file mode 100755 index 0000000000..df6ca5d087 --- /dev/null +++ b/testsuite/test_0020/README @@ -0,0 +1,4 @@ +Test Object Path #8519 + +author: sebastien ortega + diff --git a/testsuite/test_0020/data/builtin_shapes.usda b/testsuite/test_0020/data/builtin_shapes.usda new file mode 100755 index 0000000000..cc345b01b8 --- /dev/null +++ b/testsuite/test_0020/data/builtin_shapes.usda @@ -0,0 +1,55 @@ +#usda 1.0 +( + defaultPrim = "cube" +) + +def Cube "cube" +{ + double size=2 + float3 xformOp:translate= (4.8,0, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] +} +def Sphere "sphere" +{ + double radius=1.8 + float3 xformOp:translate= (-4.8,0, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] +} + +def Xform "xform" ( + +) +{ + + def Xform "Geom" + { + def Cylinder "cylinder" + { + double radius=1.1 + double height=3 + token axis="Y" + float3 xformOp:translate= (0,0, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] + + + + } + + def Cone "cone" + { + double radius=1.6 + double height=2.7 + token axis="X" + float3 xformOp:translate= (0,5, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + } + def Capsule "capsule" + { + double radius=1.6 + double height=2.7 + token axis="X" + float3 xformOp:translate= (4,5, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } +} \ No newline at end of file diff --git a/testsuite/test_0020/data/test.ass b/testsuite/test_0020/data/test.ass new file mode 100755 index 0000000000..2582e4d673 --- /dev/null +++ b/testsuite/test_0020/data/test.ass @@ -0,0 +1,111 @@ +### exported: Tue Dec 18 15:45:58 2018 +### from: Arnold 5.2.2.0 [30b8ba14] windows icc-17.0.2 oiio-2.0.1 osl-1.10.1 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 2018/12/04 22:02:04 +### host app: MtoA 3.1.3.wip 7d48f6c4 (develop) Maya 2018 +### bounds: -1 -1 -1 1 1 1 +### user: blaines +### render_layer: defaultRenderLayer +### scene: D:/arnold/scenes/usd_builtin.ma + + + +options +{ + AA_samples 3 + AA_samples_max 8 + outputs "RGBA RGBA myfilter mydriver" + xres 960 + yres 540 + texture_per_file_stats on + texture_automip off + camera "perspShape" + frame 1 + GI_diffuse_depth 1 + GI_specular_depth 1 + GI_transmission_depth 8 + declare render_layer constant STRING + render_layer "defaultRenderLayer" +} + +gaussian_filter +{ + name myfilter +} + +driver_tiff +{ + name mydriver + filename "testrender.tif" + color_space "sRGB" +} + +persp_camera +{ + name perspShape + matrix + 0.99999392 -1.08420217e-19 0.00349065149 0 + 0.000781565788 0.974611521 -0.223901182 0 + -0.00340202916 0.223902553 0.97460562 0 + -0.949623287 7.26941013 21.0998859 1 + near_clip 0.100000001 + far_clip 10000 + screen_window_min -1 -1 + screen_window_max 1 1 + shutter_start 0 + shutter_end 0 + shutter_type "box" + rolling_shutter "off" + rolling_shutter_duration 0 + motion_start 0 + motion_end 0 + exposure 0 + fov 54.4322243 + uv_remap 0 0 0 1 + declare maya_full_name constant STRING + maya_full_name "|persp|perspShape" +} + +distant_light +{ + name directionalLightShape1 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 0 0 1 + exposure 0 + cast_shadows on + cast_volumetric_shadows on + shadow_density 1 + samples 1 + normalize on + diffuse 1 + specular 1 + sss 1 + indirect 1 + max_bounces 999 + volume_samples 2 + volume 1 + aov "default" + angle 0 + declare maya_full_name constant STRING + maya_full_name "|directionalLight1|directionalLightShape1" +} + +usd +{ + name aiUsdShape1 + visibility 255 + matrix + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + 0 0 0 1 + use_light_group off + override_nodes off + filename "builtin_shapes.usda" + object_path "/xform/Geom" + frame 1 + declare maya_full_name constant STRING + maya_full_name "|aiUsd1|aiUsdShape1" +} + diff --git a/testsuite/test_0020/ref/reference.log b/testsuite/test_0020/ref/reference.log new file mode 100755 index 0000000000..70ee51f17a --- /dev/null +++ b/testsuite/test_0020/ref/reference.log @@ -0,0 +1,180 @@ +00:00:00 58MB | log started Tue Jul 2 11:35:38 2019 +00:00:00 59MB | Arnold 5.4.0.0 [6ce40857] windows icc-17.0.2 oiio-2.1.0 osl-1.11.0 vdb-4.0.0 clm-1.0.3.513 rlm-12.4.2 optix-6.0.0 2019/06/13 15:06:18 +00:00:00 59MB | running on REM8WCK8D2, pid=10940 +00:00:00 59MB | 2 x Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz (20 cores, 40 logical) with 65456MB +00:00:00 59MB | NVIDIA driver version 430.64 (Optix 60100) +00:00:00 59MB | GPU 0: GeForce RTX 2080 Ti @ 1635MHz (compute 7.5) with 11264MB (10990MB available) (NVLink:0) +00:00:00 59MB | GPU 1: Quadro K620 @ 1124MHz (compute 5.0) with 2048MB (1588MB available) (NVLink:0) +00:00:00 59MB | Windows 7 Enterprise Edition Service Pack 1 (version 6.1, build 7601) +00:00:00 59MB | soft limit for open files raised from 512 to 2048 +00:00:00 59MB | +00:00:00 59MB | loading plugins from D:\arnold\usd_procedural\build\windows_x86_64\msvc_opt\usd-0.19.5_arnold-5.4.0.0\procedural ... +00:00:00 59MB | usd_proc.dll: usd uses Arnold 5.4.0.0 +00:00:00 59MB | loaded 1 plugins from 1 lib(s) in 0:00.77 +00:00:00 59MB | loading plugins from D:\arnold\releases\Arnold_latest-windows\bin\..\plugins ... +00:00:00 59MB | alembic_proc.dll: alembic uses Arnold 5.4.0.0 +00:00:00 59MB | cryptomatte.dll: cryptomatte uses Arnold 5.4.0.0 +00:00:00 59MB | cryptomatte.dll: cryptomatte_filter uses Arnold 5.4.0.0 +00:00:00 59MB | cryptomatte.dll: cryptomatte_manifest_driver uses Arnold 5.4.0.0 +00:00:00 59MB | usd_proc.dll: usd uses Arnold 5.4.0.0 +00:00:00 59MB WARNING | node "usd" is already installed +00:00:00 59MB | loaded 5 plugins from 3 lib(s) in 0:00.07 +00:00:00 59MB | [kick] command: D:\arnold\releases\Arnold_latest-windows\bin\kick test.ass -dw -r 160 120 -bs 16 -o testrender.tif -set driver_tiff.dither false -nocrashpopup -dp -v 6 +00:00:00 59MB | loading plugins from . ... +00:00:00 59MB | no plugins loaded +00:00:00 59MB | [metadata] loading metadata file: test.ass +00:00:00 59MB | [ass] loading test.ass ... +00:00:00 60MB | [ass] read 2136 bytes, 6 nodes in 0:00.00 +00:00:00 60MB | [kick] applying 1 attr value override +00:00:00 60MB | +00:00:00 60MB | authorizing with default license managers: rlm, clm ... +00:00:03 68MB | [clm-network] authorized for "86985ARNOL_2018_0F" in 0:02.38 +00:00:03 68MB | [clm-network] expiration date: permanent, in use: 1/1000 +00:00:03 68MB | +00:00:03 69MB | [color_manager] no color manager is active +00:00:03 69MB | [color_manager] rendering color space is "linear" with declared chromaticities: +00:00:03 69MB | r(0.6400, 0.3300) g(0.3000, 0.6000) b(0.1500, 0.0600) and w(0.3127, 0.3290) +00:00:03 80MB | +00:00:03 80MB | there are 1 light and 2 objects: +00:00:03 80MB | 1 persp_camera +00:00:03 80MB | 1 distant_light +00:00:03 80MB | 1 utility +00:00:03 80MB | 1 driver_tiff +00:00:03 80MB | 1 gaussian_filter +00:00:03 80MB | 1 list_aggregate +00:00:03 80MB | 1 usd +00:00:03 80MB | +00:00:03 80MB | rendering image at 160 x 120, 3 AA samples +00:00:03 80MB | AA samples max +00:00:03 80MB | AA sample clamp +00:00:03 80MB | diffuse samples 2 / depth 1 +00:00:03 80MB | specular samples 2 / depth 1 +00:00:03 80MB | transmission samples 2 / depth 8 +00:00:03 80MB | volume indirect +00:00:03 80MB | total depth 10 +00:00:03 80MB | bssrdf samples 2 +00:00:03 80MB | transparency depth 10 +00:00:03 80MB | initializing 8 nodes ... +00:00:03 92MB | [proc] aiUsdShape1: loaded 2 nodes (2 objects, 0 shaders) +00:00:03 92MB | creating root object list ... +00:00:03 93MB | node initialization done in 0:00.09 (multithreaded) +00:00:03 93MB | updating 11 nodes ... +00:00:03 93MB | directionalLightShape1: distant_light using 1 sample, 2 volume samples +00:00:03 93MB | scene bounds: (-2.95000005 -1.5 -1.60000002) -> (1.35000002 6.5999999 1.60000002) +00:00:03 93MB | node update done in 0:00.00 (multithreaded) +00:00:03 93MB | [aov] parsing 1 output statements ... +00:00:03 93MB | [aov] registered driver: "mydriver" (driver_tiff) +00:00:03 93MB | [aov] * "RGBA" of type RGBA filtered by "myfilter" (gaussian_filter) +00:00:03 93MB | [aov] done preparing 2 AOVs for 1 output to 1 driver (0 deep AOVs) +00:00:03 93MB | starting 40 bucket workers of size 16x16 ... +00:00:03 99MB | [accel] procedural bvh4 done - 0:00.00 (wall time) - 2 prims, 1 key +00:00:03 99MB | 0% done - 173 rays/pixel +00:00:03 99MB | 5% done - 32 rays/pixel +00:00:03 100MB | 10% done - 14 rays/pixel +00:00:03 100MB | 15% done - 9 rays/pixel +00:00:03 100MB | 20% done - 28 rays/pixel +00:00:03 100MB | 25% done - 9 rays/pixel +00:00:03 100MB | 30% done - 11 rays/pixel +00:00:03 100MB | 35% done - 10 rays/pixel +00:00:03 100MB | 40% done - 5 rays/pixel +00:00:03 100MB | 45% done - 8 rays/pixel +00:00:03 100MB | 50% done - 8 rays/pixel +00:00:03 100MB | 55% done - 4 rays/pixel +00:00:03 100MB | 60% done - 3 rays/pixel +00:00:03 100MB | 65% done - 14 rays/pixel +00:00:03 100MB | 70% done - 11 rays/pixel +00:00:03 100MB | 75% done - 0 rays/pixel +00:00:03 100MB | 80% done - 0 rays/pixel +00:00:03 100MB | 85% done - 0 rays/pixel +00:00:03 100MB | 90% done - 0 rays/pixel +00:00:03 100MB | 95% done - 0 rays/pixel +00:00:03 100MB | 100% done - 0 rays/pixel +00:00:03 100MB | render done in 0:00.014 +00:00:03 100MB | [driver_tiff] writing file `testrender.tif' +00:00:03 101MB | render done +00:00:03 101MB | +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | scene creation time 0:01.08 machine utilization (0.04%) +00:00:03 101MB | plugin loading 0:00.84 +00:00:03 101MB | unaccounted 0:00.23 +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | frame time 0:02.52 machine utilization (2.11%) +00:00:03 101MB | node init 0:00.09 +00:00:03 101MB | rendering 0:00.01 +00:00:03 101MB | pixel rendering 0:00.01 +00:00:03 101MB | unaccounted 0:02.40 +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | top session self-times by category +00:00:03 101MB | InitializeNodes 0:00.09 (61.15%) +00:00:03 101MB | worker waiting 0:00.02 (17.38%) +00:00:03 101MB | Plugin loader 0:00.02 (13.82%) +00:00:03 101MB | thread blocked 0:00.00 ( 2.75%) +00:00:03 101MB | node_init (aiUsdShape1) 0:00.00 ( 1.57%) +00:00:03 101MB | initializeAllNodes 0:00.00 ( 1.57%) +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | top session self-times by node +00:00:03 101MB | InitializeNodes 0:00.09 (61.15%) +00:00:03 101MB | worker waiting 0:00.02 (17.38%) +00:00:03 101MB | Plugin loader 0:00.02 (13.82%) +00:00:03 101MB | usd:aiUsdShape1 0:00.00 ( 3.20%) +00:00:03 101MB | node_init 0:00.00 ( 1.57%) +00:00:03 101MB | thread blocked 0:00.00 ( 1.44%) +00:00:03 101MB | initializeAllNodes 0:00.00 ( 1.57%) +00:00:03 101MB | thread blocked 0:00.00 ( 1.31%) +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | peak CPU memory used 101.05MB +00:00:03 101MB | at startup 36.86MB +00:00:03 101MB | plugins 5.23MB +00:00:03 101MB | AOV samples 6.52MB +00:00:03 101MB | output buffers 0.23MB +00:00:03 101MB | framebuffers 0.31MB +00:00:03 101MB | node overhead 0.00MB +00:00:03 101MB | message passing 0.08MB +00:00:03 101MB | memory pools 30.05MB +00:00:03 101MB | geometry 0.00MB +00:00:03 101MB | accel. structs 0.01MB +00:00:03 101MB | strings 12.00MB +00:00:03 101MB | profiler 0.01MB +00:00:03 101MB | unaccounted 9.74MB +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | ray counts ( /pixel, /sample) (% total) (avg. hits) (max hits) +00:00:03 101MB | camera 192800 ( 10.04, 1.00) (100.00%) ( 0.03) ( 1) +00:00:03 101MB | total 192800 ( 10.04, 1.00) (100.00%) ( 0.03) ( 1) +00:00:03 101MB | by ray depth: 0 +00:00:03 101MB | total 100.0% +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | shader calls ( /pixel, /sample) (% total) +00:00:03 101MB | primary 6092 ( 0.32, 0.03) (100.00%) +00:00:03 101MB | total 6092 ( 0.32, 0.03) (100.00%) +00:00:03 101MB | by ray depth: 0 +00:00:03 101MB | total 100.0% +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | geometry (% hit ) (instances) ( init mem, final mem) +00:00:03 101MB | lists 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:03 101MB | procs 1 (100.0%) ( 0) ( 0.00, 0.00) +00:00:03 101MB | simple 2 (100.0%) ( 0) ( 0.00, 0.00) +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | geometric elements ( min) ( avg.) ( max) +00:00:03 101MB | objects (procs) 2 ( 2) ( 2.0) ( 2) +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | acceleration structures: (% total) +00:00:03 101MB | list 1 ( 50.00%) +00:00:03 101MB | bvh 1 ( 50.00%) +00:00:03 101MB | total 2 (100.00%) +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | number of warnings, warning type: +00:00:03 101MB | 1: node "%s" is already installed +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 101MB | performance warnings: +00:00:03 101MB WARNING | Rendering CPU utilization was only 2%. Your render may be bound by a single threaded process or I/O. +00:00:03 101MB WARNING | Scene creation was a significant amount of total time (30%). Consider optimizing this process first. +00:00:03 101MB | ----------------------------------------------------------------------------------- +00:00:03 96MB | +00:00:03 96MB | releasing resources +00:00:03 81MB | unloading 4 plugins +00:00:03 81MB | closing usd_proc.dll ... +00:00:03 76MB | closing alembic_proc.dll ... +00:00:03 76MB | closing cryptomatte.dll ... +00:00:03 76MB | closing usd_proc.dll ... +00:00:03 74MB | unloading plugins done +00:00:03 74MB | Arnold shutdown diff --git a/testsuite/test_0020/ref/reference.tif b/testsuite/test_0020/ref/reference.tif new file mode 100755 index 0000000000..84ef8e4bbc Binary files /dev/null and b/testsuite/test_0020/ref/reference.tif differ diff --git a/third_party/houdini/scripts/python/husdshadertranslators/__init__.py b/third_party/houdini/scripts/python/husdshadertranslators/__init__.py new file mode 100755 index 0000000000..0260537a02 --- /dev/null +++ b/third_party/houdini/scripts/python/husdshadertranslators/__init__.py @@ -0,0 +1 @@ +__path__ = __import__('pkgutil').extend_path(__path__, __name__) \ No newline at end of file diff --git a/third_party/houdini/scripts/python/husdshadertranslators/arnold.py b/third_party/houdini/scripts/python/husdshadertranslators/arnold.py new file mode 100755 index 0000000000..3f14e24117 --- /dev/null +++ b/third_party/houdini/scripts/python/husdshadertranslators/arnold.py @@ -0,0 +1,174 @@ +import hou +import husdshadertranslators.utils as utils +from husdshadertranslators.default import DefaultShaderTranslatorHelper, renderContextName, RampParmTranslator + +from pxr import Usd, UsdShade, Sdf, Vt + +from itertools import izip + + +# TODO(pal): +# - Support putting fetch nodes in the middle of the shader graph. +# - Investigate animated parameters, especially the ramp. +# - Filter the extra parameters created on the ramp nodes. + +# Arnold shaders have the render mask of VMantra. This would be great to change +# as mantra and other shader types might share this mask. +ARNOLD_RENDER_MASK = 'VMantra' +ARNOLD_TERMINALS = [hou.shaderType.Surface, hou.shaderType.Displacement, 'volume'] +ARNOLD_NODE_PREFIX = 'arnold::' +ARNOLD_USD_PREFIX = 'arnold:' +ARNOLD_FETCH_NAME = 'arnold::fetch' +ARNOLD_RENDER_CONTEXT_NAME = 'arnold' +ARNOLD_RAMP_TYPES = ['arnold::ramp_rgb', 'arnold::ramp_float'] +ARNOLD_RAMP_INTERP_REMAP = { + hou.rampBasis.Constant: 0, + hou.rampBasis.Linear: 1, + hou.rampBasis.CatmullRom: 2, + hou.rampBasis.BSpline: 2, + hou.rampBasis.MonotoneCubic: 3, +} + +def resolve_fetch_vop(node): + while node.type().name() == ARNOLD_FETCH_NAME: + if node.isBypassed(): + return None + node = node.parm('target').evalAsNode() + if not node: + return None + return node + +class ArnoldRampParmTranslator(RampParmTranslator): + """ + Translator for Arnold ramp shader params. + """ + + def createAndSetAttrib(self, usd_shader, time_code): + """ Creates an attribute on the usd shader primitive and sets its value + according to the member node parameter, at the specified time code. + """ + ramp = self.valueFromParm(self.parmTuple(), time_code)[0] + output_time_code = self.adjustTimeCode(time_code) + + position = usd_shader.CreateInput('position', Sdf.ValueTypeNames.FloatArray) + position.Set(Vt.FloatArray(ramp.keys()), output_time_code) + + interpolation = usd_shader.CreateInput('interpolation', Sdf.ValueTypeNames.IntArray) + interpolation.Set([ARNOLD_RAMP_INTERP_REMAP.get(v, 3) for v in ramp.basis()], output_time_code) + + if ramp.isColor(): + value_input = usd_shader.CreateInput('color', Sdf.ValueTypeNames.Color3fArray) + value = ramp.values() + else: + value_input = usd_shader.CreateInput('value', Sdf.ValueTypeNames.FloatArray) + value = Vt.FloatArray(ramp.values()) + value_input.Set(value, output_time_code) + +class ArnoldShaderHelper(DefaultShaderTranslatorHelper): + # Just initializing the default shader translator helper. + def __init__(self, translator_id, usd_stage, usd_material_path, usd_time_code): + DefaultShaderTranslatorHelper.__init__(self, translator_id, usd_stage, usd_material_path, usd_time_code) + + def createShaderPrimID(self, shader_prim, shader_node): + """ + Creates and sets the id parameter on the shader. We are querying the shader_node's type name and removing the + arnold:: prefix, and setting the id to arnold: + """ + type_name = shader_node.type().name() + if type_name.startswith(ARNOLD_NODE_PREFIX): + shader_name = type_name[len(ARNOLD_NODE_PREFIX):] + shader_prim.SetShaderId(ARNOLD_USD_PREFIX + shader_name) + # Falling back to the built-in function. + else: + DefaultShaderTranslatorHelper.createShaderPrimID(self, shader_prim, shader_node) + + def createShaderPrimAttributes(self, shader_prim, shader_node): + """ Creates and sets the shader parameters on the usd shader + based on the given shader node. + """ + for parm_tuple in shader_node.parmTuples(): + parm_template = parm_tuple.parmTemplate() + if isinstance(parm_template, hou.FolderParmTemplate) or isinstance(parm_template, hou.FolderSetParmTemplate): + continue + + parm_translator = self.getParmTranslator(parm_tuple) + if parm_translator is None: + continue + + # Create an attribute on the usd prim and set its value. + parm_translator.createAndSetAttrib(shader_prim, self.timeCode()) + + def getRampParmTranslator(self, parm_tuple): + """ Returns a translator for ramp parameters. + """ + if parm_tuple.node().type().name() not in ARNOLD_RAMP_TYPES: + return None + return ArnoldRampParmTranslator(parm_tuple) + + def getRenderContextName(self, shader_node, shader_node_output_name): + """ Returns the name of the render context to be used in material + output name. + """ + # We are only calling this helper on arnold shader, so we can just + # hardcode the value. + return ARNOLD_RENDER_CONTEXT_NAME + +class ArnoldShaderTranslator(object): + def __init__(self): + self.my_id = -1 + + def setTranslatorID(self, translator_id): + self.my_id = translator_id + + def translatorID(self): + return self.my_id + + def matchesRenderMask(self, render_mask): + return render_mask == ARNOLD_RENDER_MASK + + def createMaterialShader(self, usd_stage, usd_material_path, usd_time_code, shader_node, shader_type, output_name): + """ Creates a USD shader primitive that is part of the USD material + Ie, the translator will connect the shader to the material output. + + usd_stage - UsdStage object on which to create the shader. + usd_material_path - Path to the material primitive + in which to create the shader. + usd_time_code - time code (frame) at which to evaluate shader + parameters and at which to set the primitive attributes. + shader_node - Houdini node representing a shader. + shader_type - Requested shader type to use, in case + the shader node implements several shaders + (eg, is a material builder). + outupt_name - Particular output of the Houdini node that was + used to arrive at the shader node and which represents the + shader to translate (in case the node has several shaders). + The output name can be an empty string, if node has no outputs. + """ + shader_node = resolve_fetch_vop(shader_node) + if shader_node is None: + return + type_name = shader_node.type().name() + # If type name is 'arnold_material' then we are working with an output node, and we need to check the different + # terminals. Otherwise we are just dealing with the first node. + shaders_to_translate = [] + if type_name == 'arnold_material': + shaders_to_translate = [(input, terminal) for input, terminal in izip(shader_node.inputs(), ARNOLD_TERMINALS) + if input is not None] + elif type_name.startswith(ARNOLD_NODE_PREFIX): + shaders_to_translate = [(shader_node, ARNOLD_TERMINALS[0])] + else: + # If we are dealing with non-arnold materials, we are running the default shader translator. + helper = DefaultShaderTranslatorHelper(self.translatorID(), usd_stage, usd_material_path, usd_time_code) + helper.createMaterialShader(shader_node, shader_type, output_name) + return + + for shader, shader_type in shaders_to_translate: + shader = resolve_fetch_vop(shader) + if shader and not shader.isBypassed(): + helper = ArnoldShaderHelper(self.translatorID(), usd_stage, usd_material_path, usd_time_code) + helper.createMaterialShader(shader, shader_type, output_name) + +arnold_translator = ArnoldShaderTranslator() + +def usdShaderTranslator(): + return arnold_translator diff --git a/third_party/houdini/soho/parameters/HdArnoldRendererPlugin_Geometry.ds b/third_party/houdini/soho/parameters/HdArnoldRendererPlugin_Geometry.ds new file mode 100755 index 0000000000..6b553b920b --- /dev/null +++ b/third_party/houdini/soho/parameters/HdArnoldRendererPlugin_Geometry.ds @@ -0,0 +1,894 @@ +#include "$HFS/houdini/soho/parameters/CommonMacros.ds" + +{ + name "arnold" + label "Arnold" + parmtag { spare_opfilter "!!SHOP/PROPERTIES!!" } + parmtag { spare_classtags "render" } + + parm { + name "arnoldtransform_type_control" + label "transform_type" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:transform_type" + label "Transform Type" + type ordinal + size 1 + default { 0 } + range { 0! 2! } + parmtag { "spare_category" "Geometry" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "int" } + menu { + "0" "Linear" + "1" "Rotate About Origin" + "2" "Rotate About Center" + } + disablewhen "{ arnoldtransform_type_control == block } { arnoldtransform_type_control == none }" + } + + parm { + name "arnoldinvert_normals_control" + label "invert_normals" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:invert_normals" + label "Invert Normals" + type toggle + size 1 + default { 0 } + parmtag { "spare_category" "Geometry" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "bool" } + disablewhen "{ arnoldinvert_normals_control == block } { arnoldinvert_normals_control == none }" + } + + parm { + name "arnoldsmoothing_control" + label "smoothing" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:smoothing" + label "Smoothing" + type toggle + size 1 + default { 0 } + parmtag { "spare_category" "Geometry" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "bool" } + disablewhen "{ arnoldsmoothing_control == block } { arnoldsmoothing_control == none }" + } + + parm { + name "arnoldsubdiv_type_control" + label "subdiv_type" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:subdiv_type" + label "Subdivision Type" + type ordinal + size 1 + default { 0 } + range { 0! 2! } + parmtag { "spare_category" "Geometry" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "int" } + menu { + "0" "None" + "1" "Catmull-Clark" + "2" "Linear" + } + disablewhen "{ arnoldsubdiv_type_control == block } { arnoldsubdiv_type_control == none }" + } + + parm { + name "arnoldsubdiv_iterations_control" + label "subdiv_iterations" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:subdiv_iterations" + label "Subdivision Iterations" + type int + size 1 + default { 1 } + range { 0! 8 } + parmtag { "spare_category" "Geometry" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "int" } + disablewhen "{ arnoldsubdiv_iterations_control == block } { arnoldsubdiv_iterations_control == none }" + } + + parm { + name "arnoldsubdiv_smooth_derivs_control" + label "subdiv_smooth_derivs" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:subdiv_smooth_derivs" + label "Subdivision Smooth Derivates" + type toggle + size 1 + default { 0 } + parmtag { "spare_category" "Geometry" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "bool" } + disablewhen "{ arnoldsubdiv_smooth_derivs_control == block } { arnoldsubdiv_smooth_derivs_control == none }" + } + + parm { + name "arnoldsubdiv_uv_smoothing_control" + label "subdiv_uv_smoothing" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:subdiv_uv_smoothing" + label "Subdivision UV Smoothing" + type ordinal + size 1 + default { 0 } + range { 0! 3! } + parmtag { "spare_category" "Geometry" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "int" } + menu { + "0" "Pin Corners" + "1" "Pin Borders" + "2" "Linear" + "3" "Smooth" + } + disablewhen "{ arnoldsubdiv_uv_smoothing_control == block } { arnoldsubdiv_uv_smoothing_control == none }" + } + + parm { + name "arnoldsubdiv_frustum_ignore_control" + label "subdiv_frustum_ignore" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:subdiv_frustum_ignore" + label "Subdivision Ignore Frustum" + type toggle + size 1 + default { 0 } + parmtag { "spare_category" "Geometry" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "bool" } + disablewhen "{ arnoldsubdiv_frustum_ignore_control == block } { arnoldsubdiv_frustum_ignore_control == none }" + } + + parm { + name "arnoldsubdiv_adaptive_error_control" + label "subdiv_adaptive_error" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:subdiv_adaptive_error" + label "Subdivision Adaptive Error" + type float + size 1 + default { 0 } + range { 0! 2 } + parmtag { "spare_category" "Geometry" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "float" } + disablewhen "{ arnoldsubdiv_adaptive_error_control == block } { arnoldsubdiv_adaptive_error_control == none }" + } + + parm { + name "arnoldsubdiv_adaptive_metric_control" + label "subdiv_adaptive_metric" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:subdiv_adaptive_metric" + label "Subdivision Adaptive Metric" + type ordinal + size 1 + default { 0 } + range { 0! 2! } + parmtag { "spare_category" "Geometry" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "int" } + menu { + "0" "Auto" + "1" "Edge Length" + "2" "Flatness" + } + disablewhen "{ arnoldsubdiv_adaptive_metric_control == block } { arnoldsubdiv_adaptive_metric_control == none }" + } + + parm { + name "arnoldsubdiv_adaptive_space_control" + label "subdiv_adaptive_space" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:subdiv_adaptive_space" + label "Subdivision Adaptive Space" + type ordinal + size 1 + default { 0 } + range { 0! 1! } + parmtag { "spare_category" "Geometry" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "int" } + menu { + "0" "Raster" + "1" "Object" + } + disablewhen "{ arnoldsubdiv_adaptive_space_control == block } { arnoldsubdiv_adaptive_space_control == none }" + } + + parm { + name "arnolddisp_padding_control" + label "disp_padding" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:disp_padding" + label "Displacement Padding" + type float + size 1 + default { 0 } + range { 0 1 } + parmtag { "spare_category" "Geometry" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "float" } + disablewhen "{ arnolddisp_padding_control == block } { arnolddisp_padding_control == none }" + } + + parm { + name "arnolddisp_height_control" + label "disp_height" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:disp_height" + label "Displacement Height" + type float + size 1 + default { 1 } + range { 0 1 } + parmtag { "spare_category" "Geometry" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "float" } + disablewhen "{ arnolddisp_height_control == block } { arnolddisp_height_control == none }" + } + + parm { + name "arnolddisp_zero_value_control" + label "disp_zero_value" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:disp_zero_value" + label "Displacement Zero Value" + type float + size 1 + default { 0 } + range { 0 1 } + parmtag { "spare_category" "Geometry" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "float" } + disablewhen "{ arnolddisp_zero_value_control == block } { arnolddisp_zero_value_control == none }" + } + + parm { + name "arnolddisp_autobump_control" + label "disp_autobump" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:disp_autobump" + label "Displacement Autobump" + type toggle + size 1 + default { 0 } + parmtag { "spare_category" "Ray Flags" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "bool" } + disablewhen "{ arnolddisp_autobump_control == block } { arnolddisp_autobump_control == none }" + } + + parm { + name "arnoldopaque_control" + label "opaque" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:opaque" + label "Opaque" + type toggle + size 1 + default { 1 } + parmtag { "spare_category" "Ray Flags" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "bool" } + disablewhen "{ arnoldopaque_control == block } { arnoldopaque_control == none }" + } + + parm { + name "arnoldmatte_control" + label "matte" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:matte" + label "Matte" + type toggle + size 1 + default { 0 } + parmtag { "spare_category" "Ray Flags" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "bool" } + disablewhen "{ arnoldmatte_control == block } { arnoldmatte_control == none }" + } + + parm { + name "arnoldvisibilitycamera_control" + label "visibility_camera" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:visibility:camera" + label "Camera Ray Visibility" + type toggle + size 1 + default { 1 } + parmtag { "spare_category" "Ray Flags" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "bool" } + disablewhen "{ arnoldvisibilitycamera_control == block } { arnoldvisibilitycamera_control == none }" + } + + parm { + name "arnoldvisibilityshadow_control" + label "visibility_shadow" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:visibility:shadow" + label "Shadow Ray Visibility" + type toggle + size 1 + default { 1 } + parmtag { "spare_category" "Ray Flags" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "bool" } + disablewhen "{ arnoldvisibilityshadow_control == block } { arnoldvisibilityshadow_control == none }" + } + + parm { + name "arnoldvisibilitydiffuse_transmit_control" + label "visibility_diffuse_transmit" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:visibility:diffuse_transmit" + label "Diffuse Transmit Ray Visibility" + type toggle + size 1 + default { 1 } + parmtag { "spare_category" "Ray Flags" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "bool" } + disablewhen "{ arnoldvisibilitydiffuse_transmit_control == block } { arnoldvisibilitydiffuse_transmit_control == none }" + } + + parm { + name "arnoldvisibilityspecular_transmit_control" + label "visibility_specular_transmit" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:visibility:specular_transmit" + label "Specular Transmit Ray Visibility" + type toggle + size 1 + default { 1 } + parmtag { "spare_category" "Ray Flags" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "bool" } + disablewhen "{ arnoldvisibilityspecular_transmit_control == block } { arnoldvisibilityspecular_transmit_control == none }" + } + + parm { + name "arnoldvisibilityvolume_control" + label "visibility_volume" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:visibility:volume" + label "Volume Ray Visibility" + type toggle + size 1 + default { 1 } + parmtag { "spare_category" "Ray Flags" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "bool" } + disablewhen "{ arnoldvisibilityvolume_control == block } { arnoldvisibilityvolume_control == none }" + } + + parm { + name "arnoldvisibilitydiffuse_reflect_control" + label "visibility_diffuse_reflect" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:visibility:diffuse_reflect" + label "Diffuse Reflect Ray Visibility" + type toggle + size 1 + default { 1 } + parmtag { "spare_category" "Ray Flags" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "bool" } + disablewhen "{ arnoldvisibilitydiffuse_reflect_control == block } { arnoldvisibilitydiffuse_reflect_control == none }" + } + + parm { + name "arnoldvisibilityspecular_reflect_control" + label "visibility_specular_reflect" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:visibility:specular_reflect" + label "Specular Reflect Ray Visibility" + type toggle + size 1 + default { 1 } + parmtag { "spare_category" "Ray Flags" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "bool" } + disablewhen "{ arnoldvisibilityspecular_reflect_control == block } { arnoldvisibilityspecular_reflect_control == none }" + } + + parm { + name "arnoldvisibilitysubsurface_control" + label "visibility_subsurface_reflect" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:visibility:subsurface" + label "Subsurface Ray Visibility" + type toggle + size 1 + default { 1 } + parmtag { "spare_category" "Ray Flags" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "bool" } + disablewhen "{ arnoldvisibilitysubsurface_control == block } { arnoldvisibilitysubsurface_control == none }" + } + + parm { + name "arnoldsidednesscamera_control" + label "sidedness_camera" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:sidedness:camera" + label "Camera Ray Sidedness" + type toggle + size 1 + default { 1 } + parmtag { "spare_category" "Ray Flags" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "bool" } + disablewhen "{ arnoldsidednesscamera_control == block } { arnoldsidednesscamera_control == none }" + } + + parm { + name "arnoldsidednessshadow_control" + label "sidedness_shadow" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:sidedness:shadow" + label "Shadow Ray Sidedness" + type toggle + size 1 + default { 1 } + parmtag { "spare_category" "Ray Flags" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "bool" } + disablewhen "{ arnoldsidednessshadow_control == block } { arnoldsidednessshadow_control == none }" + } + + parm { + name "arnoldsidednessdiffuse_transmit_control" + label "sidedness_diffuse_transmit" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:sidedness:diffuse_transmit" + label "Diffuse Transmit Ray Sidedness" + type toggle + size 1 + default { 1 } + parmtag { "spare_category" "Ray Flags" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "bool" } + disablewhen "{ arnoldsidednessdiffuse_transmit_control == block } { arnoldsidednessdiffuse_transmit_control == none }" + } + + parm { + name "arnoldsidednessspecular_transmit_control" + label "sidedness_specular_transmit" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:sidedness:specular_transmit" + label "Specular Transmit Ray Sidedness" + type toggle + size 1 + default { 1 } + parmtag { "spare_category" "Ray Flags" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "bool" } + disablewhen "{ arnoldsidednessspecular_transmit_control == block } { arnoldsidednessspecular_transmit_control == none }" + } + + parm { + name "arnoldsidednessvolume_control" + label "sidedness_volume" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:sidedness:volume" + label "Volume Ray Sidedness" + type toggle + size 1 + default { 1 } + parmtag { "spare_category" "Ray Flags" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "bool" } + disablewhen "{ arnoldsidednessvolume_control == block } { arnoldsidednessvolume_control == none }" + } + + parm { + name "arnoldsidednessdiffuse_reflect_control" + label "sidedness_diffuse_reflect" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:sidedness:diffuse_reflect" + label "Diffuse Reflect Ray Sidedness" + type toggle + size 1 + default { 1 } + parmtag { "spare_category" "Ray Flags" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "bool" } + disablewhen "{ arnoldsidednessdiffuse_reflect_control == block } { arnoldsidednessdiffuse_reflect_control == none }" + } + + parm { + name "arnoldsidednessspecular_reflect_control" + label "sidedness_specular_reflect" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:sidedness:specular_reflect" + label "Specular Reflect Ray Sidedness" + type toggle + size 1 + default { 1 } + parmtag { "spare_category" "Ray Flags" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "bool" } + disablewhen "{ arnoldsidednessspecular_reflect_control == block } { arnoldsidednessspecular_reflect_control == none }" + } + + parm { + name "arnoldsidednesssubsurface_control" + label "sidedness_subsurface_reflect" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:sidedness:subsurface" + label "Subsurface Ray Sidedness" + type toggle + size 1 + default { 1 } + parmtag { "spare_category" "Ray Flags" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "bool" } + disablewhen "{ arnoldsidednesssubsurface_control == block } { arnoldsidednesssubsurface_control == none }" + } + + parm { + name "arnoldtoon_id_control" + label "toon_id" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:toon_id" + label "Toon ID" + type string + size 1 + default { "" } + parmtag { "spare_category" "Ray Flags" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "string" } + disablewhen "{ arnoldtoon_id_control == block } { arnoldtoon_id_control == none }" + } + +} diff --git a/third_party/houdini/soho/parameters/HdArnoldRendererPlugin_Light.ds b/third_party/houdini/soho/parameters/HdArnoldRendererPlugin_Light.ds new file mode 100755 index 0000000000..c2028f4c91 --- /dev/null +++ b/third_party/houdini/soho/parameters/HdArnoldRendererPlugin_Light.ds @@ -0,0 +1,525 @@ +#include "$HFS/houdini/soho/parameters/CommonMacros.ds" + +{ + name "arnold" + label "Arnold" + parmtag { spare_opfilter "!!SHOP/PROPERTIES!!" } + parmtag { spare_classtags "render" } + + parm { + name "arnoldsamples_control" + label "samples" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:samples" + label "Samples" + type int + size 1 + default { 1 } + range { 0! 8 } + parmtag { "spare_category" "Light" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "int" } + disablewhen "{ arnoldsamples_control == block } { arnoldsamples_control == none }" + } + + parm { + name "arnoldvolume_samples_control" + label "volume_samples" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:volume_samples" + label "Volume Samples" + type int + size 1 + default { 2 } + range { 0! 8 } + parmtag { "spare_category" "Light" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "int" } + disablewhen "{ arnoldvolume_samples_control == block } { arnoldvolume_samples_control == none }" + } + + parm { + name "arnoldangle_control" + label "angle" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:angle" + label "Angle" + type float + size 1 + default { 0 } + range { 0! 90 } + parmtag { "spare_category" "Light" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "float" } + disablewhen "{ arnoldangle_control == block } { arnoldangle_control == none }" + } + + parm { + name "arnoldresolution_control" + label "resolution" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:resolution" + label "Resolution" + type int + size 1 + default { 512 } + range { 0! 1024 } + parmtag { "spare_category" "Light" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "int" } + disablewhen "{ arnoldresolution_control == block } { arnoldresolution_control == none }" + } + + parm { + name "arnoldroundness_control" + label "roundness" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:roundness" + label "Roundness" + type float + size 1 + default { 0 } + range { 0! 1 } + parmtag { "spare_category" "Light" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "float" } + disablewhen "{ arnoldroundness_control == block } { arnoldroundness_control == none }" + } + + parm { + name "arnoldsoft_edge_control" + label "soft_edge" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:soft_edge" + label "Soft Edge" + type float + size 1 + default { 0 } + range { 0! 1 } + parmtag { "spare_category" "Light" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "float" } + disablewhen "{ arnoldsoft_edge_control == block } { arnoldsoft_edge_control == none }" + } + + parm { + name "arnoldspread_control" + label "spread" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:spread" + label "Spread" + type float + size 1 + default { 1 } + range { 0! 1 } + parmtag { "spare_category" "Light" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "float" } + disablewhen "{ arnoldspread_control == block } { arnoldspread_control == none }" + } + + parm { + name "arnoldportal_control" + label "portal" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:portal" + label "Portal" + type toggle + size 1 + default { 0 } + parmtag { "spare_category" "Light" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "bool" } + disablewhen "{ arnoldportal_control == block } { arnoldportal_control == none }" + } + + parm { + name "arnoldcast_shadows_control" + label "cast_shadows" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:cast_shadows" + label "Cast Shadows" + type toggle + size 1 + default { 1 } + parmtag { "spare_category" "Light" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "bool" } + disablewhen "{ arnoldcast_shadows_control == block } { arnoldcast_shadows_control == none }" + } + + parm { + name "arnoldcast_volumetric_shadows_control" + label "cast_volumetric_shadows" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:cast_volumetric_shadows" + label "Cast Volumetric Shadows" + type toggle + size 1 + default { 1 } + parmtag { "spare_category" "Light" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "bool" } + disablewhen "{ arnoldcast_volumetric_shadows_control == block } { arnoldcast_volumetric_shadows_control == none }" + } + + parm { + name "arnoldshadow_density_control" + label "shadow_density" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:shadow_density" + label "Shadow Density" + type float + size 1 + default { 0 } + range { 0! 1 } + parmtag { "spare_category" "Light" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "float" } + disablewhen "{ arnoldshadow_density_control == block } { arnoldshadow_density_control == none }" + } + + parm { + name "arnoldshadow_color_control" + label "shadow_color" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:shadow_color" + label "Shadow Color" + type color + size 3 + default { 0 0 0 } + parmtag { "spare_category" "Light" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "float3" } + disablewhen "{ arnoldshadow_color_control == block } { arnoldshadow_color_control == none }" + } + + + parm { + name "arnoldcamera_control" + label "camera" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:camera" + label "Camera Weight" + type float + size 1 + default { 0 } + range { 0! 1 } + parmtag { "spare_category" "Light" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "float" } + disablewhen "{ arnoldcamera_control == block } { arnoldcamera_control == none }" + } + + parm { + name "arnoldtransmission_control" + label "transmission" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:transmission:camera" + label "Transmission Weight" + type float + size 1 + default { 0 } + range { 0! 1 } + parmtag { "spare_category" "Light" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "float" } + disablewhen "{ arnoldtransmission_control == block } { arnoldtransmission_control == none }" + } + + parm { + name "arnolddiffuse_control" + label "diffuse" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:diffuse" + label "Diffuse Weight" + type float + size 1 + default { 1 } + range { 0! 1 } + parmtag { "spare_category" "Light" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "float" } + disablewhen "{ arnolddiffuse_control == block } { arnolddiffuse_control == none }" + } + + parm { + name "arnoldspecular_control" + label "specular" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:specular" + label "Specular Weight" + type float + size 1 + default { 1 } + range { 0! 1 } + parmtag { "spare_category" "Light" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "float" } + disablewhen "{ arnoldspecular_control == block } { arnoldspecular_control == none }" + } + + parm { + name "arnoldsss_control" + label "sss" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:sss" + label "SubSurface Weight" + type float + size 1 + default { 1 } + range { 0! 1 } + parmtag { "spare_category" "Light" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "float" } + disablewhen "{ arnoldsss_control == block } { arnoldsss_control == none }" + } + + parm { + name "arnoldindirect_control" + label "indirect" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:indirect" + label "Indirect Weight" + type float + size 1 + default { 1 } + range { 0! 1 } + parmtag { "spare_category" "Light" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "float" } + disablewhen "{ arnoldindirect_control == block } { arnoldindirect_control == none }" + } + + parm { + name "arnoldvolume_control" + label "volume" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:volume" + label "Volume Weight" + type float + size 1 + default { 1 } + range { 0! 1 } + parmtag { "spare_category" "Light" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "float" } + disablewhen "{ arnoldvolume_control == block } { arnoldvolume_control == none }" + } + + parm { + name "arnoldmax_bounces_control" + label "max_bounces" + type string + default { "none" } + menujoin { + "set" "Set or Create" + "setexisting" "Set if Exists" + "block" "Block" + "none" "Do Nothing" + } + } + + parm { + name "primvars:arnold:max_bounces" + label "Max Bounces" + type int + size 1 + default { 999 } + range { 0! 1000 } + parmtag { "spare_category" "Light" } + parmtag { "uiscope" "None" } + parmtag { "usdvaluetype" "int" } + disablewhen "{ arnoldmax_bounces_control == block } { arnoldmax_bounces_control == none }" + } +} \ No newline at end of file diff --git a/third_party/houdini/soho/parameters/HdArnoldRendererPlugin_Viewport.ds b/third_party/houdini/soho/parameters/HdArnoldRendererPlugin_Viewport.ds new file mode 100755 index 0000000000..8d5c8c14ba --- /dev/null +++ b/third_party/houdini/soho/parameters/HdArnoldRendererPlugin_Viewport.ds @@ -0,0 +1,468 @@ +#include "$HFS/houdini/soho/parameters/CommonMacros.ds" + +{ + name "arnold" + label "Arnold" + parmtag { spare_opfilter "!!SHOP/PROPERTIES!!" } + parmtag { spare_classtags "render" } + + parm { + name "enable_progressive_render" + label "Enable Progressive Render" + type toggle + size 1 + default { 1 } + help "Wether or not to use progressive rendering" + + parmtag { "spare_category" "Rendering" } + parmtag { "uiscope" "viewport toolbar" } + parmtag { "usdvaluetype" "bool" } + } + + parm { + name "progressive_min_AA_samples" + label "Progressive Render Minimum AA Samples" + type int + size 1 + default { -4 } + range { -4 4 } + help "Number of AA samples used for the first progressive iteration.." + + parmtag { "spare_category" "Rendering" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "int" } + } + + parm { + name "enable_adaptive_sampling" + label "Enable Adaptive Sampling" + type toggle + size 1 + default { 0 } + help "Wether or not Adaptive Sampling is enabled" + + parmtag { "spare_category" "Sampling" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "bool" } + } + + parm { + name "enable_gpu_rendering" + label "Enable GPU Rendering" + type toggle + size 1 + default { 0 } + help "Wether or not to use the GPU if supported" + + parmtag { "spare_category" "Rendering" } + parmtag { "uiscope" "viewport toolbar" } + parmtag { "usdvaluetype" "bool" } + } + + parm { + name "interactive_target_fps" + label "Interactive Target FPS" + type float + size 1 + default { 30 } + range { 1! 60 } + help "Target FPS for Interactive Rendering" + + parmtag { "spare_category" "Rendering" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "float" } + } + + parm { + name "interactive_target_fps_min" + label "Interactive Target FPS Minimum" + type float + size 1 + default { 20 } + range { 1! 30 } + help "Minimum Target FPS for Interactive Rendering" + + parmtag { "spare_category" "Rendering" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "float" } + } + + parm { + name "interactive_fps_min" + label "Interactive FPS Minimum" + type float + size 1 + default { 5 } + range { 1! 15 } + help "Minimum FPS for Interactive Rendering" + + parmtag { "spare_category" "Rendering" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "float" } + } + + parm { + name "threads" + label "Number of Threads" + type int + size 1 + default { -1 } + range { -1 0 } + help "Number of Threads used for rendering." + + parmtag { "spare_category" "Rendering" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "int" } + } + + parm { + name "AA_samples" + label "AA Samples" + type int + size 1 + default { 10 } + range { 1 16 } + help "Number of Anti-Aliasing samples." + + parmtag { "spare_category" "Sampling" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "int" } + } + + parm { + name "AA_samples_max" + label "AA Samples Maximum" + type int + size 1 + default { 20 } + range { 1 30 } + help "Maximum number of Anti-Aliasing samples for adaptive rendering." + + parmtag { "spare_category" "Sampling" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "int" } + } + + parm { + name "GI_diffuse_samples" + label "Diffuse Samples" + type int + size 1 + default { 1 } + range { 0! 10 } + help "Number of diffuse samples." + + parmtag { "spare_category" "Sampling" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "int" } + } + + parm { + name "GI_specular_samples" + label "Specular Samples" + type int + size 1 + default { 1 } + range { 0! 10 } + help "Number of specular samples." + + parmtag { "spare_category" "Sampling" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "int" } + } + + parm { + name "GI_transmission_samples" + label "Transmission Samples" + type int + size 1 + default { 1 } + range { 0! 10 } + help "Number of transmission samples." + + parmtag { "spare_category" "Sampling" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "int" } + } + + parm { + name "GI_subsurface_samples" + label "Subsurface Samples" + type int + size 1 + default { 1 } + range { 0! 10 } + help "Number of subsurface samples." + + parmtag { "spare_category" "Sampling" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "int" } + } + + parm { + name "GI_volume_samples" + label "Volume Samples" + type int + size 1 + default { 1 } + range { 0! 10 } + help "Number of volume samples." + + parmtag { "spare_category" "Sampling" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "int" } + } + + parm { + name "auto_transparency_depth" + label "Auto Trasparency Depth" + type int + size 1 + default { 10 } + range { 0! 50 } + help "Depth of auto transparency." + + parmtag { "spare_category" "Rendering" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "int" } + } + + parm { + name "GI_diffuse_depth" + label "Diffuse Depth" + type int + size 1 + default { 1 } + range { 0! 10 } + help "Recursion depth for diffuse samples." + + parmtag { "spare_category" "Rendering" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "int" } + } + + parm { + name "GI_specular_depth" + label "Specular Depth" + type int + size 1 + default { 1 } + range { 0! 10 } + help "Recursion depth for specular samples." + + parmtag { "spare_category" "Rendering" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "int" } + } + + parm { + name "GI_transmission_depth" + label "Transmission Depth" + type int + size 1 + default { 2 } + range { 0! 10 } + help "Recursion depth for transmission samples." + + parmtag { "spare_category" "Rendering" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "int" } + } + + parm { + name "GI_volume_depth" + label "Volume Depth" + type int + size 1 + default { 0 } + range { 0! 10 } + help "Recursion depth for volume samples." + + parmtag { "spare_category" "Rendering" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "int" } + } + + parm { + name "GI_total_depth" + label "Total Depth" + type int + size 1 + default { 10 } + range { 0! 20 } + help "Recursion depth for total samples." + + parmtag { "spare_category" "Rendering" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "int" } + } + + parm { + name "ignore_textures" + label "Ignore Textures" + type toggle + size 1 + default { 0 } + help "Ignoring textures." + + parmtag { "spare_category" "Rendering" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "bool" } + } + + parm { + name "ignore_shaders" + label "Ignore Shaders" + type toggle + size 1 + default { 0 } + help "Ignoring shaders." + + parmtag { "spare_category" "Rendering" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "bool" } + } + + parm { + name "ignore_atmosphere" + label "Ignore Atmosphere" + type toggle + size 1 + default { 0 } + help "Ignoring atmosphere." + + parmtag { "spare_category" "Rendering" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "bool" } + } + + parm { + name "ignore_lights" + label "Ignore Lights" + type toggle + size 1 + default { 0 } + help "Ignoring lights." + + parmtag { "spare_category" "Rendering" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "bool" } + } + + parm { + name "ignore_shadows" + label "Ignore shadows" + type toggle + size 1 + default { 0 } + help "Ignoring shadows." + + parmtag { "spare_category" "Rendering" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "bool" } + } + + parm { + name "ignore_subdivision" + label "Ignore Subdivision" + type toggle + size 1 + default { 0 } + help "Ignoring subdivision." + + parmtag { "spare_category" "Rendering" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "bool" } + } + + parm { + name "ignore_displacement" + label "Ignore Displacement" + type toggle + size 1 + default { 0 } + help "Ignoring displacement." + + parmtag { "spare_category" "Rendering" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "bool" } + } + + parm { + name "ignore_bump" + label "Ignore Bump" + type toggle + size 1 + default { 0 } + help "Ignoring bump." + + parmtag { "spare_category" "Rendering" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "bool" } + } + + parm { + name "ignore_motion" + label "Ignore Motion" + type toggle + size 1 + default { 0 } + help "Ignoring motion blur." + + parmtag { "spare_category" "Rendering" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "bool" } + } + + parm { + name "ignore_dof" + label "Ignore DOF" + type toggle + size 1 + default { 0 } + help "Ignoring depth of field." + + parmtag { "spare_category" "Rendering" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "bool" } + } + + parm { + name "ignore_smoothing" + label "Ignore Smooting" + type toggle + size 1 + default { 0 } + help "Ignoring smoothing." + + parmtag { "spare_category" "Rendering" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "bool" } + } + + parm { + name "ignore_sss" + label "Ignore SSS" + type toggle + size 1 + default { 0 } + help "Ignoring subsurface scattering." + + parmtag { "spare_category" "Rendering" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "bool" } + } + + parm { + name "ignore_operators" + label "Ignore Operators" + type toggle + size 1 + default { 0 } + help "Ignoring operators." + + parmtag { "spare_category" "Rendering" } + parmtag { "uiscope" "viewport" } + parmtag { "usdvaluetype" "bool" } + } +} diff --git a/tools/scons-custom/site_tools/clang.py b/tools/scons-custom/site_tools/clang.py new file mode 100755 index 0000000000..13fce19f96 --- /dev/null +++ b/tools/scons-custom/site_tools/clang.py @@ -0,0 +1,138 @@ +# Copyright 2019 Autodesk, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +""" + +Tool-specific initialization for clang. + +""" + +import utils as sa +import os +import glob +import re +from sets import Set +import SCons + +def split_version(v): + """Splits a version string 'a.b.c' into an int list [a, b, c]""" + try: + s = [int(x) for x in v.split('.')] + except ValueError: + return [] + return s + +def closest_version(v, vlist): + """See if we can match v (string) in vlist (list of strings) + If user requests v=13, it will return the greatest 13.x version. + If user requests v=13.1, it will return the greatest 13.1.x version, and so on""" + if not v: + return vlist[0] + s = split_version(v) + l = len(s) + # Try to match the latest installed version of the requested version + if l > 0: + for vi in vlist: + S = split_version(vi) + if l > len(S): + continue + n = 0 + for i in range(l): + if s[i] == S[i]: n = n + 1 + else: break + if n == l: + return vi + return None + +def generate(env, version=None): + # Configure tool names + clang_name = { + 'linux' : r'^(?Pclang)?$', + 'darwin': r'^(?Pclang)(?P-mp-.\..)?$', + }.get(sa.system.os) + macro_version = ['__clang_major__','__clang_minor__','__clang_patchlevel__'] + # Look for clang installations in the PATH and other custom places + toolchain_path = Set(os.environ[sa.system.PATH].split(os.pathsep)) + toolchain_path.update({ + 'linux' : glob.glob(os.path.join(os.sep, 'solidangle', 'toolchain', '*', 'bin')), + 'darwin': [os.path.join(os.sep, 'opt', 'local', 'bin')], + }.get(sa.system.os, [])) + versions_detected = {} + for p in toolchain_path: + if os.path.isdir(p): + clang_name_match = [f for f in os.listdir(p) if re.search(clang_name, f)] + for clang in clang_name_match: + clang_path = os.path.realpath(os.path.join(p, clang)) + if os.path.isfile(clang_path): + v = repr(sa.compiler.detect_version(env, clang_path, macro_version)) + paths = versions_detected.get(v, []) + if clang_path not in paths: paths.append(clang_path) + versions_detected[v] = paths + + if not versions_detected.keys(): + raise SCons.Errors.UserError("Can't find Clang.") + # Try to match the closest detected version + selected_version = closest_version(version, versions_detected.keys()) + path = versions_detected.get(selected_version) + if not path: + raise SCons.Errors.UserError("Can't find Clang %s. " % version + + "Installed versions are [%s]." % (', '.join(versions_detected.keys()))) + if len(path) > 1: + # Warn if we found multiple installations of a given version + class ClangWarning(SCons.Warnings.Warning): pass + SCons.Warnings.enableWarningClass(ClangWarning) + SCons.Warnings.warn(ClangWarning, 'Multiple installations for Clang %s in [%s]' % (selected_version, ', '.join(path))) + + clang_path, clang_exec = os.path.split(path[0]) + m = re.match(clang_name, clang_exec) + if m: + exec_name = m.group('exec') + suffix = m.group('suffix') + if suffix is None: suffix = '' + else: + exec_name = 'clang' + suffix = '' + env['CC'] = clang_exec + env['CXX'] = exec_name + '++' + suffix + if sa.system.is_linux: + # In order to use LTO, we need the gold linker, which is able to load plugins + env['LD'] = 'ld.gold' + + env.PrependENVPath(sa.system.PATH, clang_path) + # Use LLVM's tools if they are present in the detected LLVM's path + for i in ('AR', 'RANLIB'): + tool = 'llvm-{0}{1}'.format(i.lower(), suffix) + if os.path.exists(os.path.join(clang_path, tool)): + env[i] = tool + # Check the presence of the LLVM Gold plugin, needed for LTO + if sa.system.is_linux: + env['LLVM_GOLD_PLUGIN'] = os.path.join(clang_path, os.pardir, 'lib', 'LLVMgold.so') + if not os.path.exists(env['LLVM_GOLD_PLUGIN']): + raise SCons.Errors.UserError("Can't find LLVM Gold plugin") + env['COMPILER_VERSION_DETECTED'] = sa.compiler.detect_version(env, env['CC'], macro_version) + env['COMPILER_VERSION_INSTALLED'] = versions_detected.keys() + [apple] = sa.compiler.get_defines(env, env['CC'], ['__apple_build_version__']) + if apple: + env['COMPILER_PREFIX'] = 'apple' + + # If requested, detect and configure the Clang's static analyzer (scan-build) + # More info at http://clang-analyzer.llvm.org/ + if env['STATIC_ANALYSIS']: + static_analyzer = ['scan-build'] + static_analyzer += [] # scan-build options + if os.path.exists(os.path.join(clang_path, static_analyzer[0])): + env['CC'] = ' '.join(static_analyzer + [env['CC'] ]) + env['CXX'] = ' '.join(static_analyzer + [env['CXX']]) + +def exists(env): + return True diff --git a/tools/scons-custom/site_tools/doxygen/__init__.py b/tools/scons-custom/site_tools/doxygen/__init__.py new file mode 100755 index 0000000000..c2f751661d --- /dev/null +++ b/tools/scons-custom/site_tools/doxygen/__init__.py @@ -0,0 +1,15 @@ +# Copyright 2019 Autodesk, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from builder import generate +from builder import exists diff --git a/tools/scons-custom/site_tools/doxygen/builder.py b/tools/scons-custom/site_tools/doxygen/builder.py new file mode 100755 index 0000000000..9d19b70c4a --- /dev/null +++ b/tools/scons-custom/site_tools/doxygen/builder.py @@ -0,0 +1,94 @@ +# Copyright 2019 Autodesk, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os + +import SCons.Action +import SCons.Builder +import SCons.Errors +import SCons.Node +import SCons.Scanner +import SCons.Script + +import doxyfile + +## load our own python modules +import utils as sa + +def _scanner(node, env, path): + with open(node.abspath, 'r') as f: + sources = doxyfile.sources(f, env['ROOT_DIR']) + return sources + +def _scan_check(node, env): + # Should we scan this node for dependencies? + return os.path.isfile(node.abspath) + +def _emitter(target, source, env): + # Create a local construction environment for just adding an internal builder + # which generates a Doxyfile from a python dictionary with tags and values + local_env = env.Clone() + local_env['BUILDERS']['Doxyfile'] = doxyfile.builder + # Parse the source Doxyfile, returning a dictionary with tags and values ... + old_doxyfile = source[0].abspath + with open(old_doxyfile, 'r') as f: + tags = doxyfile.parse(f) + # ... and override with the dictionary provided in env['DOXYGEN_TAGS'] + tags.update(env.get('DOXYGEN_TAGS', {})) + # Build the new Doxyfile file from the updated dictionary (and properly + # defining the dependencies) + tags_value = SCons.Node.Python.Value(tags) + env.Depends(tags_value, source) + new_doxyfile = os.path.join(env['BUILD_BASE_DIR'], 'Doxyfile') + local_env.Doxyfile(new_doxyfile, tags_value) + # We set the doxygen target to the output directory. + new_target = env.Dir(os.path.join(target[0].abspath, 'html')) + return [new_target], [new_doxyfile] + +def _action(target, source, env): + # Extract some tags for adding them to the execution environment + with open(source[0].abspath, 'r') as f: + tags = doxyfile.parse(f) + env_tags = {k: tags[k] for k in ['PROJECT_NAME', 'PROJECT_NUMBER']} + # Transfer the system PATH to the execution environment + env_tags['PATH'] = os.environ['PATH'] + # Execute doxygen with the source Doxyfile + r, o = sa.system.execute('doxygen {}'.format(source[0].abspath), env=env_tags) + if r: + raise SCons.Errors.UserError('[Errno {}] doxygen: {}'.format(r, '\n'.join(o))) + print 'file://{}'.format(target[0].abspath) + return None + +def generate(env): + # Detect Doxygen and get the version + r, o = sa.system.execute('doxygen --version') + if r: + return + # Message when executing the Doxygen builder + action_message = 'Building SDK documentation with Doxygen {} ...'.format(o[0]) + # Add the Doxygen builder to the construction environment + env['BUILDERS']['Doxygen'] = SCons.Builder.Builder( + action = SCons.Action.Action(_action, action_message), + emitter = _emitter, + target_factory = SCons.Node.FS.Entry, + source_factory = SCons.Node.FS.File, + single_target = True, + single_source = True, + source_scanner = SCons.Scanner.Scanner( + function = _scanner, + scan_check = _scan_check, + ) + ) + +def exists(env): + return env.Detect('doxygen') diff --git a/tools/scons-custom/site_tools/doxygen/doxyfile.py b/tools/scons-custom/site_tools/doxygen/doxyfile.py new file mode 100755 index 0000000000..a782c1116e --- /dev/null +++ b/tools/scons-custom/site_tools/doxygen/doxyfile.py @@ -0,0 +1,153 @@ +# Copyright 2019 Autodesk, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os +from fnmatch import fnmatch + +import SCons.Action +import SCons.Builder +import SCons.Node + +def _action(target, source, env): + with open(target[0].abspath, 'w') as f: + for k, v in source[0].value.items(): + if hasattr(v, '__iter__'): + v = ' '.join(v) + f.write('{} = {}\n'.format(k, v)) + return None + +builder = SCons.Builder.Builder( + action = SCons.Action.Action(_action, None), + target_factory = SCons.Node.FS.File, + source_factory = SCons.Node.Python.Value, + single_target = True, + single_source = True, +) + +def sources(f, root_dir): + default_file_patterns = [ '*.cpp', '*.h', '*.md', '*.py' ] + + data = parse(f) + + recursive = data.get('RECURSIVE', 'NO') == 'YES' + f_pat = data.get('FILE_PATTERNS', []) + f_pat = f_pat if f_pat else default_file_patterns + f_exc = data.get('EXCLUDE_PATTERNS', []) + input = data.get('INPUT', []) + input = input if input else [root_dir] + + sources = [] + + for i in input: + if not os.path.isabs(i): + i = os.path.join(root_dir, i) + if os.path.isfile(i): + sources.append(i) + elif os.path.isdir(i): + if recursive: + for root, dirs, files in os.walk(i): + for fn in files: + included = reduce(lambda x, y: x or fnmatch(fn, y), f_pat, False) if f_pat else True + excluded = reduce(lambda x, y: x and fnmatch(fn, y), f_exc, True ) if f_exc else False + if included and not excluded: + sources.append(os.path.join(root, fn)) + else: + for pattern in f_pat: + sources.extend(glob.glob(os.path.join(i, pattern))) + + # TODO: Process also @INCLUDE and TAGFILES + + return sources + +def parse(f): + """ + Parse a Doxygen source file and return a dictionary of all the values. + Values will be strings and lists of strings. + """ + data = {} + + import shlex + lex = shlex.shlex(instream=f, posix=True) + lex.wordchars += "*+./-:@" + lex.whitespace = lex.whitespace.replace("\n", "") + lex.escape = "" + + conf_dir = os.path.dirname(f.name) + + lineno = lex.lineno + token = lex.get_token() + key = None + last_token = "" + key_token = True # The first token should be a key. + next_key = False + new_data = True + + def append_data(data, key, new_data, token): + if new_data or len(data[key]) == 0: + data[key].append(token) + else: + data[key][-1] += token + + while token: + if token in ['\n']: + if last_token not in ['\\']: + key_token = True + elif token in ['\\']: + pass + elif key_token: + key = token + key_token = False + else: + if token == "+=": + if key not in data: + data[key] = [] + elif token == "=": + if key == "TAGFILES" and key in data: + append_data(data, key, False, "=") + new_data = False + elif key == "@INCLUDE" and key in data: + # don't reset the @INCLUDE list when we see a new @INCLUDE line. + pass + else: + data[key] = [] + elif key == "@INCLUDE": + # special case for @INCLUDE key: read the referenced + # file as a doxyfile too. + nextfile = token + if not os.path.isabs(nextfile): + nextfile = os.path.join(conf_dir, nextfile) + if nextfile in data[key]: + raise Exception("recursive @INCLUDE in Doxygen config: " + nextfile) + data[key].append(nextfile) + fh = open(nextfile, 'r') + DoxyfileParse(fh.read(), conf_dir, data) + fh.close() + else: + append_data(data, key, new_data, token) + new_data = True + + last_token = token + token = lex.get_token() + + if last_token == '\\' and token != '\n': + new_data = False + append_data(data, key, new_data, '\\') + + # Compress lists of len 0 and 1 into single strings and keep some tags as lists + for k, v in data.items(): + keep_list = k in ['INPUT', 'FILE_PATTERNS', 'EXCLUDE_PATTERNS', 'TAGFILES', '@INCLUDE'] + if keep_list : continue + elif len(v) == 0: data[k] = '' + elif len(v) == 1: data[k] = v[0] + + return data diff --git a/tools/scons-custom/site_tools/intelc.py b/tools/scons-custom/site_tools/intelc.py new file mode 100755 index 0000000000..107cd5437b --- /dev/null +++ b/tools/scons-custom/site_tools/intelc.py @@ -0,0 +1,849 @@ +"""SCons.Tool.icl + +Tool-specific initialization for the Intel C/C++ compiler. +Supports Linux and Windows compilers, v7 and up. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from __future__ import division + +__revision__ = "src/engine/SCons/Tool/intelc.py 2013/03/03 09:48:35 garyo" + +import math, sys, os.path, glob, string, re, subprocess, shlex +import utils as sa +from utils.version import Version + +is_windows = sys.platform == 'win32' +is_win64 = is_windows and (os.environ['PROCESSOR_ARCHITECTURE'] == 'AMD64' or + ('PROCESSOR_ARCHITEW6432' in os.environ and + os.environ['PROCESSOR_ARCHITEW6432'] == 'AMD64')) +is_linux = sys.platform.startswith('linux') +is_mac = sys.platform == 'darwin' + +if is_windows: + import SCons.Tool.msvc +elif is_linux: + import SCons.Tool.gcc +elif is_mac: + import SCons.Tool.gcc +import SCons.Util +import SCons.Warnings + +# Exceptions for this tool +class IntelCError(SCons.Errors.InternalError): + pass +class MissingRegistryError(IntelCError): # missing registry entry + pass +class MissingDirError(IntelCError): # dir not found + pass +class NoRegistryModuleError(IntelCError): # can't read registry at all + pass + +# In windows this will hold the root entry in the registry for every detected +# intel compiler version. In linux the root directory is stored instead. +detected_versions = {} + +# In order to update the following table with Intel Compiler versions +# we can check the official Intel's article: +# http://software.intel.com/en-us/articles/intel-compiler-and-composer-update-version-numbers-to-compiler-version-number-mapping + +if is_windows: + # In windows we can only query the register for 'Version Major', + # 'Version Minor' and 'Revision' (aka build number). + # From version 12.0 (Intel C++ Composer XE 2011) the build number maps + # to a given patch level (aka Update number) + known_versions = { + # (major, minor, patch):[major,minor,update]) + (17,0,210):[17,0,4], ## Composer XE 2017 Update 4 + (17,0,187):[17,0,2], ## Composer XE 2017 Update 2 + (17,0,143):[17,0,1], ## Composer XE 2017 Update 1 + (17,0,109):[17,0,0], ## Composer XE 2017 + (16,0,246):[16,0,4], ## Composer XE 2016 Update 4 + (16,0,207):[16,0,3], # . + (16,0,180):[16,0,2], # . + (16,0,146):[16,0,1], ## Composer XE 2016 Update 1 + (16,0,110):[16,0,0], ## Composer XE 2016 + (15,0,287):[15,0,7], ## Composer XE 2015 Update 7 + (15,0,285):[15,0,6], # . + (15,0,280):[15,0,5], # . + (15,0,221):[15,0,4], # . + (15,0,208):[15,0,3], # . + (15,0,179):[15,0,2], # . + (15,0,148):[15,0,1], ## Composer XE 2015 Update 1 + (15,0,108):[15,0,0], ## Composer XE 2015 + (14,0,237):[14,0,4], ## Composer XE 2013 SP1 Update 4 + (14,0,202):[14,0,3], # . + (14,0,176):[14,0,2], # . + (14,0,139):[14,0,1], ## Composer XE 2013 SP1 Update 1 + (14,0,103):[14,0,0], ## Composer XE 2013 SP1 + (13,1,198):[13,1,3], ## Composer XE 2013 Update 5 + (13,1,190):[13,1,2], # . + (13,1,171):[13,1,1], # . + (13,1,149):[13,1,0], # . + (13,0,119):[13,0,1], ## Composer XE 2013 Update 1 + (13,0, 89):[13,0,0], ## Composer XE 2013 + (12,1,371):[12,1,7], ## Composer XE 2011 SP1 Update 13 + (12,1,369):[12,1,6], # . + (12,1,344):[12,1,5], # . + (12,1,325):[12,1,4], # . + (12,1,300):[12,1,3], # . + (12,1,278):[12,1,2], # . + (12,1,258):[12,1,1], # . + (12,1,233):[12,1,0], ## Composer XE 2011 SP1 Update 6 + (12,0,221):[12,0,5], ## Composer XE 2011 Update 5 + (12,0,196):[12,0,4], # . + (12,0,175):[12,0,3], # . + (12,0,154):[12,0,2], # . + (12,0,128):[12,0,1], ## Composer XE 2011 Update 1 + (12,0,104):[12,0,0] ## Composer XE 2011 + } + +if is_linux: + # In linux we have to directly ask icc/icpc for the definition of + # '__INTEL_COMPILER_BUILD_DATE', which maps to a given version. + # This macro was introduced from icc 8.1 and it's guaranteed to be + # an increasing number with every update. We can't + # only rely on '__INTEL_COMPILER' since it only report the major and minor + # version and there's no way to discover the patch level. + # We can dump those macros by executing + # $ icpc -dM -E -x c++ /dev/null + known_versions = { + # __INTEL_COMPILER_BUILD_DATE:[major,minor,[update,]patch] + '20170428':[17,0,4,196], ## Composer XE 2017 Update 4 + '20170404':[17,0,3,191], # . + '20170213':[17,0,2,174], # . + '20161005':[17,0,1,132], ## Composer XE 2017 Update 1 + '20160721':[17,0,0, 98], ## Composer XE 2017 + '20160811':[16,0,4,258], ## Composer XE 2016 Update 4 + '20160415':[16,0,3,210], # . + '20160204':[16,0,2,181], # . + '20151021':[16,0,1,150], ## Composer XE 2016 Update 1 + '20150816':[16,0,0,109], ## Composer XE 2016 + '20160518':[15,0,7,235], ## Composer XE 2015 Update 7 + '20151119':[15,0,6,233], # . + '20150805':[15,0,5,232], ## Composer XE 2015 Update 5 + '20150407':[15,0,3,187], ## Composer XE 2015 Update 3 + '20150121':[15,0,2,164], # . + '20141023':[15,0,1,133], ## Composer XE 2015 Update 1 + '20140723':[15,0,0, 90], ## Composer XE 2015 + '20140805':[14,0,4,211], ## Composer XE 2013 SP1 Update 4 + '20140422':[14,0,3,174], # . + '20140120':[14,0,2,144], # . + '20131008':[14,0,1,106], ## Composer XE 2013 SP1 Update 1 + '20130728':[14,0,0, 80], ## Composer XE 2013 SP1 + '20130607':[13,1,3,192], ## Composer XE 2013 Update 5 + '20130514':[13,1,2,183], # . + '20130313':[13,1,1,163], # . + '20130121':[13,1,0,146], # . + '20121010':[13,0,1,117], ## Composer XE 2013 Update 1 + '20120731':[13,0,0, 79], ## Composer XE 2013 + '20120928':[12,1,7,367], ## Composer XE 2011 SP1 Update 13 + '20120821':[12,1,6,361], # . + '20120612':[12,1,5,339], # . + '20120410':[12,1,4,319], # . + '20120212':[12,1,3,293], # . + '20111128':[12,1,2,273], # . + '20111011':[12,1,1,256], # . + '20110811':[12,1,0,233], ## Composer XE 2011 SP1 Update 6 + '20110719':[12,0,5,220], ## Composer XE 2011 Update 5 + '20110427':[12,0,4,191], # . + '20110309':[12,0,3,174], # . + '20110117':[12,0,2,137], # . + '20101116':[12,0,1,108], ## Composer XE 2011 Update 1 + '20101006':[12,0,0, 84], ## Composer XE 2011 + '20110708':[11,1, 80], ## Compiler Pro 11.1 Update 9 + '20101201':[11,1, 75], # . + '20100806':[11,1, 73], # . + '20100414':[11,1, 72], # . + '20100203':[11,1, 69], # . + '20091130':[11,1, 64], # . + '20091012':[11,1, 59], # . + '20090827':[11,1, 56], # . + '20090630':[11,1, 46], ## Compiler Pro 11.1 Update 1 + '20090511':[11,1, 38], ## Compiler Pro 11.1 + '20090609':[11,0, 84] + } + +if is_mac: + # The version in OSX is defined the same way as in linux, through the + # predefined macro '__INTEL_COMPILER_BUILD_DATE', which maps to a given version. + # FIXME: intel built versions 16.0.0 and 15.0.5 the same day, so this + # translates in a duplicated entry in the dictionary (key '20150805'). + # In any case, it's not a big deal, since we are not using icc in OSX. + known_versions = { + # __INTEL_COMPILER_BUILD_DATE:[major,minor,[update,]patch] + '20170430':[17,0,4,181], ## Composer XE 2017 Update 4 + '20170213':[17,0,2,163], ## Composer XE 2017 Update 2 + '20161013':[17,0,1,126], ## Composer XE 2017 Update 1 + '20160721':[17,0,0,102], ## Composer XE 2017 + '20160811':[16,0,4,210], ## Composer XE 2016 Update 4 + '20160416':[16,0,3,170], # + '20160204':[16,0,2,146], # . + '20151020':[16,0,1,111], ## Composer XE 2016 Update 1 + '20150805':[16,0,0, 83], ## Composer XE 2016 + '20160518':[15,0,7,234], ## Composer XE 2015 Update 7 + '20151124':[15,0,6,232], # . + '20150805':[15,0,5,222], ## Composer XE 2015 Update 5 + '20150407':[15,0,3,187], ## Composer XE 2015 Update 3 + '20150121':[15,0,2,132], # . + '20141022':[15,0,1,108], ## Composer XE 2015 Update 1 + '20140716':[15,0,0, 77], ## Composer XE 2015 + '20140815':[14,0,4,201], ## Composer XE 2013 SP1 Update 4 + '20140421':[14,0,3,166], # . + '20140121':[14,0,2,139], # . + '20131010':[14,0,1,103], ## Composer XE 2013 SP1 Update 1 + '20130710':[14,0,0, 65], ## Composer XE 2013 SP1 + '20130606':[13,0,3,198], ## Composer XE 2013 Update 5 + '20130314':[13,0,2,171], ## Composer XE 2013 Update 3 + '20121010':[13,0,1,119], ## Composer XE 2013 Update 1 + '20120731':[13,0,0, 88] ## Composer XE 2013 + } + +def linux_ver_normalize(vstr): + """Normalize a Linux compiler version number. + Intel changed from "80" to "9.0" in 2005, so we assume if the number + is greater than 60 it's an old-style number and otherwise new-style. + Always returns an old-style float like 80 or 90 for compatibility with Windows. + Shades of Y2K!""" + # Check for version number like 9.1.026: return 91.026 + # XXX needs to be updated for 2011+ versions (like 2011.11.344 which is compiler v12.1.5) + m = re.match(r'([0-9]+)\.([0-9]+)\.([0-9]+)', vstr) + if m: + vmaj,vmin,build = m.groups() + return float(vmaj) * 10. + float(vmin) + float(build) / 1000.; + else: + f = float(vstr) + if is_windows: + return f + else: + if f < 60: return f * 10.0 + else: return f + +def check_abi(abi): + """Check for valid ABI (application binary interface) name, + and map into canonical one""" + if not abi: + return None + abi = abi.lower() + # valid_abis maps input name to canonical name + if is_windows: + valid_abis = {'ia32' : 'ia32', + 'x86' : 'ia32', + 'ia64' : 'ia64', + 'em64t' : 'em64t', + 'amd64' : 'em64t'} + if is_linux: + valid_abis = {'ia32' : 'ia32', + 'x86' : 'ia32', + 'x86_64' : 'x86_64', + 'em64t' : 'x86_64', + 'amd64' : 'x86_64'} + if is_mac: + valid_abis = {'ia32' : 'ia32', + 'x86' : 'ia32', + 'x86_64' : 'x86_64', + 'em64t' : 'x86_64'} + try: + abi = valid_abis[abi] + except KeyError: + raise SCons.Errors.UserError("Intel compiler: Invalid ABI %s, valid values are %s"% \ + (abi, list(valid_abis.keys()))) + return abi + +def vercmp(a, b): + """Compare strings as floats, + but Intel changed Linux naming convention at 9.0""" + return cmp(linux_ver_normalize(b), linux_ver_normalize(a)) + +def split_version(v): + """Splits a version string 'a.b.c' into an int list [a, b, c]""" + try: + s = [int(x) for x in v.split('.')] + except ValueError: + return [] + return s + +def get_version_from_list(v, vlist): + """See if we can match v (string) in vlist (list of strings) + If user requests v=13, it will return the greatest 13.x version. + If user requests v=13.1, it will return the greatest 13.1.x version, and so on""" + s = split_version(v) + l = len(s) + # Try to match the latest installed version of the requested version + if l > 0: + for vi in vlist: + S = split_version(vi) + if l > len(S): + continue + n = 0 + for i in range(l): + if s[i] == S[i]: n = n + 1 + else: break + if n == l: + return vi + return None + +def detect_installed_versions_linux(): + versions = [] + global detected_versions + for root, dirs, names in os.walk('/opt'): + if ('icpc' in names) and not os.path.islink(os.path.join(root, 'icpc')): + cmd = str(os.path.join(root, 'icpc')) + ' -dM -E -x c++ /dev/null' + r, lines = sa.system.execute(cmd) + ver = None + for l in lines: + if l.find('__INTEL_COMPILER ') > 0: + v = int(l.split()[2]) + ver = '%u.%u' % ( int(v/100), int((v%100)/10) ) + if l.find('__INTEL_COMPILER_BUILD_DATE ') > 0: + v = known_versions.get(l.split()[2]) + if v: ver = '%u.%u.%u' % (v[0], v[1], v[2]) + break + if ver: + detected_versions[ver] = os.path.abspath(os.path.join(root, os.path.pardir, os.path.pardir)) + versions.append(ver) + return versions + +def detect_installed_versions_windows(): + def open_key(name): + try: + return SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, name) + except WindowsError: + None + + def list_subkeys(key): + subkeys = [] + while True: + try: subkey = SCons.Util.RegEnumKey(key, len(subkeys)) + except EnvironmentError: break + subkeys.append(subkey) + if 'Defaults' in subkeys: subkeys.remove('Defaults') + return subkeys + + def get_value(key, name): + try: + values = [] + for n in name: + try: v = SCons.Util.RegQueryValueEx(key, n)[0] + except WindowsError: v = None + values.append(v) + return tuple(values) + except TypeError: + try: v = SCons.Util.RegQueryValueEx(key, name)[0] + except WindowsError: v = None + return v + + keys = [] + root = 'Software\\Wow6432Node\\Intel\\' if is_win64 else 'Software\\Intel\\' + for base in ['Compilers\\C++', 'Suites']: + name = '{}\\{}'.format(root, base) + key = open_key(name) + if not key: + continue + for version in list_subkeys(key): + name = '{}\\{}\\{}'.format(root, base, version) + key = open_key(name) + if not key: + continue + if base == 'Suites': + for uuid in list_subkeys(key): + name = '{}\\{}\\{}\\{}\\C++'.format(root, base, version, uuid) + key = open_key(name) + if not key: + continue + keys.append(name) + else: + keys.append(name) + + versions = [] + global detected_versions + + for k in keys: + key = open_key(k) + if not key: + continue + ver_nms = ['Major Version', 'Minor Version', 'Revision'] + ver_reg = get_value(key, ver_nms) + if any((x is None for x in ver_reg)): + continue + v = known_versions.get(ver_reg) + if v: ver = '%u.%u.%u' % (v[0], v[1], v[2]) + else: ver = '%u.%u.%03u' % ver_reg + versions.append(ver) + detected_versions[ver] = k + + return versions + +def get_intel_registry_value(valuename, version=None, abi=None): + """ + Return a value from the Intel compiler registry tree. (Windows only) + """ + # Open the key: + if is_win64: + ABI = '\\EM64T_NATIVE' + else: + ABI = '\\'+abi.upper() + try: + K = detected_versions[version] + ABI + k1 = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, detected_versions[version] + ABI) + k2 = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, detected_versions[version]) + except SCons.Util.RegError: + raise MissingRegistryError("%s was not found in the registry, for Intel compiler version %s, abi='%s'"%(K, version, abi)) + + # Get the value: + # First try in key 'k1' and then in 'k2' + try: + v = SCons.Util.RegQueryValueEx(k1, valuename)[0] + return v # or v.encode('iso-8859-1', 'replace') to remove unicode? + except SCons.Util.RegError: + try: + v = SCons.Util.RegQueryValueEx(k2, valuename)[0] + return v # or v.encode('iso-8859-1', 'replace') to remove unicode? + except SCons.Util.RegError: + raise MissingRegistryError("%s\\%s was not found in the registry."%(K, valuename)) + +def detect_installed_versions(): + """Returns a sorted list of strings, like "70" or "80" or "9.0" + with most recent compiler version first. + """ + versions=[] + global detected_versions + if is_windows: + versions = detect_installed_versions_windows() + if not versions or len(versions) == 0: + if is_win64: + keyname = 'Software\\WoW6432Node\\Intel\\Compilers\\C++' + else: + keyname = 'Software\\Intel\\Compilers\\C++' + try: + k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, + keyname) + except WindowsError: + return [] + i = 0 + versions = [] + try: + while i < 100: + subkey = SCons.Util.RegEnumKey(k, i) # raises EnvironmentError + # Check that this refers to an existing dir. + # This is not 100% perfect but should catch common + # installation issues like when the compiler was installed + # and then the install directory deleted or moved (rather + # than uninstalling properly), so the registry values + # are still there. + ok = False + for try_abi in ('IA32', 'IA32e', 'IA64', 'EM64T'): + try: + d = get_intel_registry_value('ProductDir', subkey, try_abi) + except MissingRegistryError: + continue # not found in reg, keep going + if os.path.exists(d): ok = True + if ok: + versions.append(subkey) + else: + try: + # Registry points to nonexistent dir. Ignore this + # version. + value = get_intel_registry_value('ProductDir', subkey, 'IA32') + except MissingRegistryError, e: + + # Registry key is left dangling (potentially + # after uninstalling). + + print \ + "scons: *** Ignoring the registry key for the Intel compiler version %s.\n" \ + "scons: *** It seems that the compiler was uninstalled and that the registry\n" \ + "scons: *** was not cleaned up properly.\n" % subkey + else: + print "scons: *** Ignoring "+str(value) + + i = i + 1 + except EnvironmentError: + # no more subkeys + pass + elif is_linux or is_mac: + versions = detect_installed_versions_linux() + if not versions or len(versions) == 0: + for d in glob.glob('/opt/intel_cc_*'): + # Typical dir here is /opt/intel_cc_80. + m = re.search(r'cc_(.*)$', d) + if m: + versions.append(m.group(1)) + for d in glob.glob('/opt/intel/cc*/*'): + # Typical dir here is /opt/intel/cc/9.0 for IA32, + # /opt/intel/cce/9.0 for EMT64 (AMD64) + m = re.search(r'([0-9][0-9.]*)$', d) + if m: + versions.append(m.group(1)) + for d in glob.glob('/opt/intel/Compiler/*'): + # Typical dir here is /opt/intel/Compiler/11.1 + m = re.search(r'([0-9][0-9.]*)$', d) + if m: + versions.append(m.group(1)) + for d in glob.glob('/opt/intel/composerxe-*'): + # Typical dir here is /opt/intel/composerxe-2011.4.184 + m = re.search(r'([0-9][0-9.]*)$', d) + if m: + versions.append(m.group(1)) + for d in glob.glob('/opt/intel/composer_xe_*'): + # Typical dir here is /opt/intel/composer_xe_2011_sp1.11.344 + # The _sp1 is useless, the installers are named 2011.9.x, 2011.10.x, 2011.11.x + m = re.search(r'([0-9]{0,4})(?:_sp\d*)?\.([0-9][0-9.]*)$', d) + if m: + versions.append("%s.%s"%(m.group(1), m.group(2))) + def keyfunc(str): + """Given a dot-separated version string, return a tuple of ints representing it.""" + return [int(x) for x in str.split('.')] + # split into ints, sort, then remove dups + return sorted(SCons.Util.unique(versions), key=keyfunc, reverse=True) + +def get_intel_compiler_top(version, abi): + """ + Return the main path to the top-level dir of the Intel compiler, + using the given version. + The compiler will be in /bin/icl.exe (icc on linux), + the include dir is /include, etc. + """ + + if is_windows: + if not SCons.Util.can_read_reg: + raise NoRegistryModuleError("No Windows registry module was found") + top = get_intel_registry_value('ProductDir', version, abi) + archdir={'x86_64': 'intel64', + 'amd64' : 'intel64', + 'em64t' : 'intel64', + 'x86' : 'ia32', + 'i386' : 'ia32', + 'ia32' : 'ia32' + }[abi] # for v11 and greater + # pre-11, icl was in Bin. 11 and later, it's in Bin/ apparently. + if not os.path.exists(os.path.join(top, "Bin", "icl.exe")) \ + and not os.path.exists(os.path.join(top, "Bin", abi, "icl.exe")) \ + and not os.path.exists(os.path.join(top, "Bin", archdir, "icl.exe")): + raise MissingDirError("Can't find Intel compiler in %s"%(top)) + elif is_mac or is_linux: + def find_in_2008style_dir(version): + # first dir is new (>=9.0) style, second is old (8.0) style. + dirs=('/opt/intel/cc/%s', '/opt/intel_cc_%s') + if abi == 'x86_64': + dirs=('/opt/intel/cce/%s',) # 'e' stands for 'em64t', aka x86_64 aka amd64 + top=None + for d in dirs: + if os.path.exists(os.path.join(d%version, "bin", "icc")): + top = d%version + break + return top + def find_in_2010style_dir(version): + dirs=('/opt/intel/Compiler/%s/*'%version) + # typically /opt/intel/Compiler/11.1/064 (then bin/intel64/icc) + dirs=glob.glob(dirs) + # find highest sub-version number by reverse sorting and picking first existing one. + dirs.sort() + dirs.reverse() + top=None + for d in dirs: + if (os.path.exists(os.path.join(d, "bin", "ia32", "icc")) or + os.path.exists(os.path.join(d, "bin", "intel64", "icc"))): + top = d + break + return top + def find_in_2011style_dir(version): + # The 2011 (compiler v12) dirs are inconsistent, so just redo the search from + # get_all_compiler_versions and look for a match (search the newest form first) + top=None + for d in glob.glob('/opt/intel/composer_xe_*'): + # Typical dir here is /opt/intel/composer_xe_2011_sp1.11.344 + # The _sp1 is useless, the installers are named 2011.9.x, 2011.10.x, 2011.11.x + m = re.search(r'([0-9]{0,4})(?:_sp\d*)?\.([0-9][0-9.]*)$', d) + if m: + cur_ver = "%s.%s"%(m.group(1), m.group(2)) + if cur_ver == version and \ + (os.path.exists(os.path.join(d, "bin", "ia32", "icc")) or + os.path.exists(os.path.join(d, "bin", "intel64", "icc"))): + top = d + break + if not top: + for d in glob.glob('/opt/intel/composerxe-*'): + # Typical dir here is /opt/intel/composerxe-2011.4.184 + m = re.search(r'([0-9][0-9.]*)$', d) + if m and m.group(1) == version and \ + (os.path.exists(os.path.join(d, "bin", "ia32", "icc")) or + os.path.exists(os.path.join(d, "bin", "intel64", "icc"))): + top = d + break + return top + def find_in_2016style_dir(version): + # The 2016 (compiler v16) dirs are inconsistent from previous. + top = None + for d in glob.glob('/opt/intel/compilers_and_libraries_%s/linux'%version): + if os.path.exists(os.path.join(d, "bin", "ia32", "icc")) or os.path.exists(os.path.join(d, "bin", "intel64", "icc")): + top = d + break + return top + + top = find_in_2016style_dir(version) or find_in_2011style_dir(version) or find_in_2010style_dir(version) or find_in_2008style_dir(version) + # print "INTELC: top=",top + top = detected_versions[version] + if not top: + raise MissingDirError("Can't find version %s Intel compiler in %s (abi='%s')"%(version,top, abi)) + return top + + +def generate(env, version=None, abi=None, topdir=None, verbose=0): + """Add Builders and construction variables for Intel C/C++ compiler + to an Environment. + args: + version: (string) compiler version to use, like "80" + abi: (string) 'win32' or whatever Itanium version wants + topdir: (string) compiler top dir, like + "c:\Program Files\Intel\Compiler70" + If topdir is used, version and abi are ignored. + verbose: (int) if >0, prints compiler version used. + """ + if not (is_mac or is_linux or is_windows): + # can't handle this platform + return + + if is_windows: + SCons.Tool.msvc.generate(env) + elif is_linux: + SCons.Tool.gcc.generate(env) + elif is_mac: + SCons.Tool.gcc.generate(env) + + # if version is unspecified, use latest + vlist = detect_installed_versions() + if not version: + if vlist: + version = vlist[0] + else: + # User may have specified '90' but we need to get actual dirname '9.0'. + # get_version_from_list does that mapping. + v = get_version_from_list(version, vlist) + if not v: + raise SCons.Errors.UserError("Invalid Intel compiler version %s: "%version + \ + "installed versions are %s"%(', '.join(vlist))) + version = v + + env['COMPILER_VERSION_DETECTED'] = Version(version) + env['COMPILER_VERSION_INSTALLED'] = vlist + + # if abi is unspecified, use ia32 + # alternatives are ia64 for Itanium, or amd64 or em64t or x86_64 (all synonyms here) + abi = check_abi(abi) + if abi is None: + if is_mac or is_linux: + # Check if we are on 64-bit linux, default to 64 then. + uname_m = os.uname()[4] + if uname_m == 'x86_64': + abi = 'x86_64' + else: + abi = 'ia32' + else: + if is_win64: + abi = 'em64t' + else: + abi = 'ia32' + + if version and not topdir: + try: + topdir = get_intel_compiler_top(version, abi) + except (SCons.Util.RegError, IntelCError): + topdir = None + + if not topdir: + # Normally this is an error, but it might not be if the compiler is + # on $PATH and the user is importing their env. + class ICLTopDirWarning(SCons.Warnings.Warning): + pass + if (is_mac or is_linux) and not env.Detect('icc') or \ + is_windows and not env.Detect('icl'): + + SCons.Warnings.enableWarningClass(ICLTopDirWarning) + SCons.Warnings.warn(ICLTopDirWarning, + "Failed to find Intel compiler for version='%s', abi='%s'"% + (str(version), str(abi))) + else: + # should be cleaned up to say what this other version is + # since in this case we have some other Intel compiler installed + SCons.Warnings.enableWarningClass(ICLTopDirWarning) + SCons.Warnings.warn(ICLTopDirWarning, + "Can't find Intel compiler top dir for version='%s', abi='%s'"% + (str(version), str(abi))) + + if topdir: + archdir={'x86_64': 'intel64', + 'amd64' : 'intel64', + 'em64t' : 'intel64', + 'x86' : 'ia32', + 'i386' : 'ia32', + 'ia32' : 'ia32' + }[abi] # for v11 and greater + if os.path.exists(os.path.join(topdir, 'bin', archdir)): + bindir="bin/%s"%archdir + libdir="lib/%s"%archdir + else: + bindir="bin" + libdir="lib" + if verbose: + print "Intel C compiler: using version %s (%g), abi %s, in '%s/%s'"%\ + (repr(version), linux_ver_normalize(version),abi,topdir,bindir) + if is_linux: + # Show the actual compiler version by running the compiler. + os.system('%s/%s/icc --version'%(topdir,bindir)) + if is_mac: + # Show the actual compiler version by running the compiler. + os.system('%s/%s/icc --version'%(topdir,bindir)) + + env['INTEL_C_COMPILER_TOP'] = topdir + if is_linux: + paths={'INCLUDE' : 'include', + 'LIB' : libdir, + 'PATH' : bindir, + 'LD_LIBRARY_PATH' : libdir} + for p in paths.keys(): + env.PrependENVPath(p, os.path.join(topdir, paths[p])) + if is_mac: + paths={'INCLUDE' : 'include', + 'LIB' : libdir, + 'PATH' : bindir, + 'LD_LIBRARY_PATH' : libdir} + for p in paths.keys(): + env.PrependENVPath(p, os.path.join(topdir, paths[p])) + if is_windows: + # env key reg valname default subdir of top + paths=(('INCLUDE', 'IncludeDir', 'Include'), + ('LIB' , 'LibDir', 'Lib'), + ('PATH' , 'BinDir', bindir)) + # We are supposed to ignore version if topdir is set, so set + # it to the emptry string if it's not already set. + if version is None: + version = '' + # Each path has a registry entry, use that or default to subdir + for p in paths: + try: + path=get_intel_registry_value(p[1], version, abi) + # These paths may have $(ICInstallDir) + # which needs to be substituted with the topdir. + path=path.replace('$(ICInstallDir)', topdir + os.sep) + except IntelCError: + # Couldn't get it from registry: use default subdir of topdir + env.PrependENVPath(p[0], os.path.join(topdir, p[2])) + else: + env.PrependENVPath(p[0], path.split(os.pathsep)) + # print "ICL %s: %s, final=%s"%(p[0], path, str(env['ENV'][p[0]])) + + if is_windows: + env['CC'] = 'icl' + env['CXX'] = 'icl' + env['LINK'] = 'xilink' + env['AR'] = 'xilib' + else: + env['CC'] = 'icc' + env['CXX'] = 'icpc' + # Don't reset LINK here; + # use smart_link which should already be here from link.py. + #env['LINK'] = '$CC' + env['AR'] = 'xiar' + env['LD'] = 'xild' # not used by default + + # This is not the exact (detailed) compiler version, + # just the major version as determined above or specified + # by the user. It is a float like 80 or 90, in normalized form for Linux + # (i.e. even for Linux 9.0 compiler, still returns 90 rather than 9.0) + if version: + env['INTEL_C_COMPILER_VERSION']=linux_ver_normalize(version) + + if is_windows: + # Look for license file dir + # in system environment, registry, and default location. + envlicdir = os.environ.get("INTEL_LICENSE_FILE", '') + K = ('SOFTWARE\Intel\Licenses') + try: + k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, K) + reglicdir = SCons.Util.RegQueryValueEx(k, "w_cpp")[0] + except (AttributeError, SCons.Util.RegError): + reglicdir = "" + defaultlicdir = r'C:\Program Files\Common Files\Intel\Licenses' + + licdir = None + for ld in [envlicdir, reglicdir]: + # If the string contains an '@', then assume it's a network + # license (port@system) and good by definition. + if ld and (ld.find('@') != -1 or os.path.exists(ld)): + licdir = ld + break + if not licdir: + licdir = defaultlicdir + if not os.path.exists(licdir): + class ICLLicenseDirWarning(SCons.Warnings.Warning): + pass + SCons.Warnings.enableWarningClass(ICLLicenseDirWarning) + SCons.Warnings.warn(ICLLicenseDirWarning, + "Intel license dir was not found." + " Tried using the INTEL_LICENSE_FILE environment variable (%s), the registry (%s) and the default path (%s)." + " Using the default path as a last resort." + % (envlicdir, reglicdir, defaultlicdir)) + env['ENV']['INTEL_LICENSE_FILE'] = licdir + + # In our CentOS 6 machines, we are using the custom gcc 4.8.2 toolchain from + # http://people.centos.org/tru/devtools-2/readme. We should point to it in + # order to use C++11 features. + if sa.system.is_linux: + gcc_toolchain = '/opt/rh/devtoolset-2/root/usr' + if os.path.exists(gcc_toolchain): + env['GCC_SUPPORT_ROOT'] = gcc_toolchain + env.PrependENVPath('PATH', os.path.join(gcc_toolchain, 'bin')) + +def exists(env): + if not (is_mac or is_linux or is_windows): + # can't handle this platform + return 0 + + try: + versions = detect_installed_versions() + except (SCons.Util.RegError, IntelCError): + versions = None + detected = versions is not None and len(versions) > 0 + if not detected: + # try env.Detect, maybe that will work + if is_windows: + return env.Detect('icl') + elif is_linux: + return env.Detect('icc') + elif is_mac: + return env.Detect('icc') + return detected + +# end of file + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-LICENSE b/tools/scons/scons-LICENSE new file mode 100755 index 0000000000..6b6cd6cd94 --- /dev/null +++ b/tools/scons/scons-LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2001 - 2019 The SCons Foundation + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tools/scons/scons-README b/tools/scons/scons-README new file mode 100755 index 0000000000..40d7217567 --- /dev/null +++ b/tools/scons/scons-README @@ -0,0 +1,249 @@ + + + SCons - a software construction tool + + Version 3.0.3 + + +This is SCons, a tool for building software (and other files). SCons is +implemented in Python, and its "configuration files" are actually Python +scripts, allowing you to use the full power of a real scripting language +to solve build problems. You do not, however, need to know Python to +use SCons effectively. + +See the RELEASE.txt file for notes about this specific release, +including known problems. See the CHANGES.txt file for a list of +changes since the previous release. + + +LATEST VERSION +============== + +Before going further, you can check that this package you have is +the latest version by checking the SCons download page at: + + http://www.scons.org/download.html + + +EXECUTION REQUIREMENTS +====================== + +Running SCons requires Python version 2.7.* or 3.5.* and above. There should be +no other dependencies or requirements to run SCons. (There is, however, +an additional requirement to *install* SCons from this particular +package; see the next section.) + +By default, SCons knows how to search for available programming tools +on various systems--see the SCons man page for details. You may, +of course, override the default SCons choices made by appropriate +configuration of Environment construction variables. + + +INSTALLATION REQUIREMENTS +========================= + +Nothing special. + + +INSTALLATION +============ + +Assuming your system satisfies the installation requirements in the +previous section, install SCons from this package simply by running the +provided Python-standard setup script as follows: + + # python setup.py install + +By default, the above command will do the following: + + -- Install the version-numbered "scons-3.0.3" and "sconsign-3.0.3" + scripts in the default system script directory (/usr/bin or + C:\Python*\Scripts, for example). This can be disabled by + specifying the "--no-version-script" option on the command + line. + + -- Install scripts named "scons" and "sconsign" scripts in the + default system script directory (/usr/bin or C:\Python*\Scripts, + for example). This can be disabled by specifying the + "--no-scons-script" option on the command line, which is useful + if you want to install and experiment with a new version before + making it the default on your system. + + On UNIX or Linux systems, you can have the "scons" and "sconsign" + scripts be hard links or symbolic links to the "scons-3.0.3" and + "sconsign-3.0.3" scripts by specifying the "--hardlink-scons" + or "--symlink-scons" options on the command line. + + -- Install "scons-3.0.3.bat" and "scons.bat" wrapper scripts in the + Python prefix directory on Windows (C:\Python*, for example). + This can be disabled by specifying the "--no-install-bat" option + on the command line. + + On UNIX or Linux systems, the "--install-bat" option may be + specified to have "scons-3.0.3.bat" and "scons.bat" files + installed in the default system script directory, which is useful + if you want to install SCons in a shared file system directory + that can be used to execute SCons from both UNIX/Linux and + Windows systems. + + -- Install the SCons build engine (a Python module) in an + appropriate version-numbered SCons library directory + (/usr/lib/scons-3.0.3 or C:\Python*\scons-3.0.3, for example). + See below for more options related to installing the build + engine library. + + -- Install the troff-format man pages in an appropriate directory + on UNIX or Linux systems (/usr/share/man/man1 or /usr/man/man1, + for example). This can be disabled by specifying the + "--no-install-man" option on the command line. The man pages + can be installed on Windows systems by specifying the + "--install-man" option on the command line. + +Note that, by default, SCons does not install its build engine library +in the standard Python library directories. If you want to be able to +use the SCons library modules (the build engine) in other Python +scripts, specify the "--standard-lib" option on the command line, as +follows: + + # python setup.py install --standard-lib + +This will install the build engine in the standard Python library +directory (/usr/lib/python*/site-packages or +C:\Python*\Lib\site-packages). + +Alternatively, you can have SCons install its build engine library in a +hard-coded standalone library directory, instead of the default +version-numbered directory, by specifying the "--standalone-lib" option +on the command line, as follows: + + # python setup.py install --standalone-lib + +This is usually not recommended, however. + +Note that, to install SCons in any of the above system directories, +you should have system installation privileges (that is, "root" or +"Administrator") when running the setup.py script. If you don't have +system installation privileges, you can use the --prefix option to +specify an alternate installation location, such as your home directory: + + $ python setup.py install --prefix=$HOME + +This will install SCons in the appropriate locations relative to +$HOME--that is, the scons script itself $HOME/bin and the associated +library in $HOME/lib/scons, for example. + + +DOCUMENTATION +============= + +See the RELEASE.txt file for notes about this specific release, +including known problems. See the CHANGES.txt file for a list of +changes since the previous release. + +The scons.1 man page is included in this package, and contains a section +of small examples for getting started using SCons. + +Additional documentation for SCons is available at: + + https://scons.org/documentation.html + + +LICENSING +========= + +SCons is distributed under the MIT license, a full copy of which is +available in the LICENSE.txt file. The MIT license is an approved Open +Source license, which means: + + This software is OSI Certified Open Source Software. OSI + Certified is a certification mark of the Open Source Initiative. + +More information about OSI certifications and Open Source software is +available at: + + http://www.opensource.org/ + + +REPORTING BUGS +============== + +Please report bugs by following the detailed instructions on our Bug +Submission page: + + http://scons.tigris.org/bug-submission.html + +You can also send mail to the SCons developers' mailing list: + + scons-dev@scons.org + +But even if you send email to the mailing list please make sure that you +ALSO submit a bug report to the project page bug tracker, because bug +reports in email often get overlooked in the general flood of messages. + + +MAILING LISTS +============= + +An active mailing list for users of SCons is available. You may send +questions or comments to the list at: + + scons-users@scons.org + +You may subscribe to the mailing list by sending email to: + + scons-users-join@scons.org + +There is also a low-volume mailing list available for announcements +about SCons. Subscribe by sending email to: + + announce-subscribe@scons.tigris.org + +There are other mailing lists available for SCons developers, for +notification of SCons code changes, and for notification of updated +bug reports and project documents. Please see our mailing lists page +for details. + + +DONATIONS +========= + +If you find SCons helpful, please consider making a donation (of cash, +software, or hardware) to support continued work on the project. +Information is available at: + + http://www.scons.org/donate.html + + +FOR MORE INFORMATION +==================== + +Check the SCons web site at: + + http://www.scons.org/ + + +AUTHOR INFO +=========== +SCons was originally written by Steven Knight, knight at baldmt dot com. +Since around 2010 it has been maintained by the SCons +development team, co-managed by Bill Deegan and Gary Oberbrunner, with +many contributors, including but not at all limited to: + +- Chad Austin +- Dirk Baechle +- Charles Crain +- William Deegan +- Steve Leblanc +- Rob Managan +- Greg Noel +- Gary Oberbrunner +- Anthony Roach +- Greg Spencer +- Tom Tanner +- Anatoly Techtonik +- Christoph Wiedemann +- Russel Winder + +\... and many others. + +Copyright (c) 2001 - 2019 The SCons Foundation diff --git a/tools/scons/scons-configure-cache.py b/tools/scons/scons-configure-cache.py new file mode 100755 index 0000000000..798b8fa2a3 --- /dev/null +++ b/tools/scons/scons-configure-cache.py @@ -0,0 +1,178 @@ +#! /usr/bin/env python +# +# SCons - a Software Constructor +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +'''Show or convert the configuration of an SCons cache directory. + +A cache of derived files is stored by file signature. +The files are split into directories named by the first few +digits of the signature. The prefix length used for directory +names can be changed by this script. +''' + +from __future__ import print_function +import argparse +import glob +import json +import os + +__revision__ = "src/script/scons-configure-cache.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +__version__ = "3.0.5" + +__build__ = "a56bbd8c09fb219ab8a9673330ffcd55279219d0" + +__buildsys__ = "kufra" + +__date__ = "2019-03-26 23:16:31" + +__developer__ = "bdeegan" + + +def rearrange_cache_entries(current_prefix_len, new_prefix_len): + '''Move cache files if prefix length changed. + + Move the existing cache files to new directories of the + appropriate name length and clean up the old directories. + ''' + print('Changing prefix length from', current_prefix_len, + 'to', new_prefix_len) + dirs = set() + old_dirs = set() + for file in glob.iglob(os.path.join('*', '*')): + name = os.path.basename(file) + dname = name[:current_prefix_len].upper() + if dname not in old_dirs: + print('Migrating', dname) + old_dirs.add(dname) + dname = name[:new_prefix_len].upper() + if dname not in dirs: + os.mkdir(dname) + dirs.add(dname) + os.rename(file, os.path.join(dname, name)) + + # Now delete the original directories + for dname in old_dirs: + os.rmdir(dname) + + +# The configuration dictionary should have one entry per entry in the +# cache config. The value of each entry should include the following: +# implicit - (optional) This is to allow adding a new config entry and also +# changing the behaviour of the system at the same time. This +# indicates the value the config entry would have had if it had +# been specified. +# default - The value the config entry should have if it wasn't previously +# specified +# command-line - parameters to pass to ArgumentParser.add_argument +# converter - (optional) Function to call if conversion is required +# if this configuration entry changes +config_entries = { + 'prefix_len': { + 'implicit': 1, + 'default': 2, + 'command-line': { + 'help': 'Length of cache file name used as subdirectory prefix', + 'metavar': '', + 'type': int + }, + 'converter': rearrange_cache_entries + } +} + +parser = argparse.ArgumentParser( + description='Modify the configuration of an scons cache directory', + epilog=''' + Unspecified options will not be changed unless they are not + set at all, in which case they are set to an appropriate default. + ''') + +parser.add_argument('cache-dir', help='Path to scons cache directory') +for param in config_entries: + parser.add_argument('--' + param.replace('_', '-'), + **config_entries[param]['command-line']) +parser.add_argument('--version', + action='version', + version='%(prog)s 1.0') +parser.add_argument('--show', + action="store_true", + help="show current configuration") + +# Get the command line as a dict without any of the unspecified entries. +args = dict([x for x in vars(parser.parse_args()).items() if x[1]]) + +# It seems somewhat strange to me, but positional arguments don't get the - +# in the name changed to _, whereas optional arguments do... +cache = args['cache-dir'] +if not os.path.isdir(cache): + raise RuntimeError("There is no cache directory named %s" % cache) +os.chdir(cache) +del args['cache-dir'] + +if not os.path.exists('config'): + # old config dirs did not have a 'config' file. Try to update. + # Validate the only files in the directory are directories 0-9, a-f + expected = ['{:X}'.format(x) for x in range(0, 16)] + if not set(os.listdir('.')).issubset(expected): + raise RuntimeError( + "%s does not look like a valid version 1 cache directory" % cache) + config = dict() +else: + with open('config') as conf: + config = json.load(conf) + +if args.get('show', None): + print("Current configuration in '%s':" % cache) + print(json.dumps(config, sort_keys=True, + indent=4, separators=(',', ': '))) + # in case of the show argument, emit some stats as well + file_count = 0 + for _, _, files in os.walk('.'): + file_count += len(files) + if file_count: # skip config file if it exists + file_count -= 1 + print("Cache contains %s files" % file_count) + del args['show'] + +# Find any keys that are not currently set but should be +for key in config_entries: + if key not in config: + if 'implicit' in config_entries[key]: + config[key] = config_entries[key]['implicit'] + else: + config[key] = config_entries[key]['default'] + if key not in args: + args[key] = config_entries[key]['default'] + +# Now go through each entry in args to see if it changes an existing config +# setting. +for key in args: + if args[key] != config[key]: + if 'converter' in config_entries[key]: + config_entries[key]['converter'](config[key], args[key]) + config[key] = args[key] + +# and write the updated config file +with open('config', 'w') as conf: + json.dump(config, conf) diff --git a/tools/scons/scons-local-3.0.5/SCons/Action.py b/tools/scons/scons-local-3.0.5/SCons/Action.py new file mode 100755 index 0000000000..861db48217 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Action.py @@ -0,0 +1,1398 @@ +"""SCons.Action + +This encapsulates information about executing any sort of action that +can build one or more target Nodes (typically files) from one or more +source Nodes (also typically files) given a specific Environment. + +The base class here is ActionBase. The base class supplies just a few +OO utility methods and some generic methods for displaying information +about an Action in response to the various commands that control printing. + +A second-level base class is _ActionAction. This extends ActionBase +by providing the methods that can be used to show and perform an +action. True Action objects will subclass _ActionAction; Action +factory class objects will subclass ActionBase. + +The heavy lifting is handled by subclasses for the different types of +actions we might execute: + + CommandAction + CommandGeneratorAction + FunctionAction + ListAction + +The subclasses supply the following public interface methods used by +other modules: + + __call__() + THE public interface, "calling" an Action object executes the + command or Python function. This also takes care of printing + a pre-substitution command for debugging purposes. + + get_contents() + Fetches the "contents" of an Action for signature calculation + plus the varlist. This is what gets MD5 checksummed to decide + if a target needs to be rebuilt because its action changed. + + genstring() + Returns a string representation of the Action *without* + command substitution, but allows a CommandGeneratorAction to + generate the right action based on the specified target, + source and env. This is used by the Signature subsystem + (through the Executor) to obtain an (imprecise) representation + of the Action operation for informative purposes. + + +Subclasses also supply the following methods for internal use within +this module: + + __str__() + Returns a string approximation of the Action; no variable + substitution is performed. + + execute() + The internal method that really, truly, actually handles the + execution of a command or Python function. This is used so + that the __call__() methods can take care of displaying any + pre-substitution representations, and *then* execute an action + without worrying about the specific Actions involved. + + get_presig() + Fetches the "contents" of a subclass for signature calculation. + The varlist is added to this to produce the Action's contents. + TODO(?): Change this to always return ascii/bytes and not unicode (or py3 strings) + + strfunction() + Returns a substituted string representation of the Action. + This is used by the _ActionAction.show() command to display the + command/function that will be executed to generate the target(s). + +There is a related independent ActionCaller class that looks like a +regular Action, and which serves as a wrapper for arbitrary functions +that we want to let the user specify the arguments to now, but actually +execute later (when an out-of-date check determines that it's needed to +be executed, for example). Objects of this class are returned by an +ActionFactory class that provides a __call__() method as a convenient +way for wrapping up the functions. + +""" + +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +__revision__ = "src/engine/SCons/Action.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os +import pickle +import re +import sys +import subprocess +import itertools +import inspect +from collections import OrderedDict + +import SCons.Debug +from SCons.Debug import logInstanceCreation +import SCons.Errors +import SCons.Util +import SCons.Subst + +# we use these a lot, so try to optimize them +from SCons.Util import is_String, is_List + +class _null(object): + pass + +print_actions = 1 +execute_actions = 1 +print_actions_presub = 0 + +# Use pickle protocol 1 when pickling functions for signature +# otherwise python3 and python2 will yield different pickles +# for the same object. +# This is due to default being 1 for python 2.7, and 3 for 3.x +# TODO: We can roll this forward to 2 (if it has value), but not +# before a deprecation cycle as the sconsigns will change +ACTION_SIGNATURE_PICKLE_PROTOCOL = 1 + + +def rfile(n): + try: + return n.rfile() + except AttributeError: + return n + + +def default_exitstatfunc(s): + return s + +strip_quotes = re.compile('^[\'"](.*)[\'"]$') + + +def _callable_contents(obj): + """Return the signature contents of a callable Python object. + """ + try: + # Test if obj is a method. + return _function_contents(obj.__func__) + + except AttributeError: + try: + # Test if obj is a callable object. + return _function_contents(obj.__call__.__func__) + + except AttributeError: + try: + # Test if obj is a code object. + return _code_contents(obj) + + except AttributeError: + # Test if obj is a function object. + return _function_contents(obj) + + +def _object_contents(obj): + """Return the signature contents of any Python object. + + We have to handle the case where object contains a code object + since it can be pickled directly. + """ + try: + # Test if obj is a method. + return _function_contents(obj.__func__) + + except AttributeError: + try: + # Test if obj is a callable object. + return _function_contents(obj.__call__.__func__) + + except AttributeError: + try: + # Test if obj is a code object. + return _code_contents(obj) + + except AttributeError: + try: + # Test if obj is a function object. + return _function_contents(obj) + + except AttributeError as ae: + # Should be a pickle-able Python object. + try: + return _object_instance_content(obj) + # pickling an Action instance or object doesn't yield a stable + # content as instance property may be dumped in different orders + # return pickle.dumps(obj, ACTION_SIGNATURE_PICKLE_PROTOCOL) + except (pickle.PicklingError, TypeError, AttributeError) as ex: + # This is weird, but it seems that nested classes + # are unpickable. The Python docs say it should + # always be a PicklingError, but some Python + # versions seem to return TypeError. Just do + # the best we can. + return bytearray(repr(obj), 'utf-8') + + +def _code_contents(code, docstring=None): + """Return the signature contents of a code object. + + By providing direct access to the code object of the + function, Python makes this extremely easy. Hooray! + + Unfortunately, older versions of Python include line + number indications in the compiled byte code. Boo! + So we remove the line number byte codes to prevent + recompilations from moving a Python function. + + See: + - https://docs.python.org/2/library/inspect.html + - http://python-reference.readthedocs.io/en/latest/docs/code/index.html + + For info on what each co\_ variable provides + + The signature is as follows (should be byte/chars): + co_argcount, len(co_varnames), len(co_cellvars), len(co_freevars), + ( comma separated signature for each object in co_consts ), + ( comma separated signature for each object in co_names ), + ( The bytecode with line number bytecodes removed from co_code ) + + co_argcount - Returns the number of positional arguments (including arguments with default values). + co_varnames - Returns a tuple containing the names of the local variables (starting with the argument names). + co_cellvars - Returns a tuple containing the names of local variables that are referenced by nested functions. + co_freevars - Returns a tuple containing the names of free variables. (?) + co_consts - Returns a tuple containing the literals used by the bytecode. + co_names - Returns a tuple containing the names used by the bytecode. + co_code - Returns a string representing the sequence of bytecode instructions. + + """ + + # contents = [] + + # The code contents depends on the number of local variables + # but not their actual names. + contents = bytearray("{}, {}".format(code.co_argcount, len(code.co_varnames)), 'utf-8') + + contents.extend(b", ") + contents.extend(bytearray(str(len(code.co_cellvars)), 'utf-8')) + contents.extend(b", ") + contents.extend(bytearray(str(len(code.co_freevars)), 'utf-8')) + + # The code contents depends on any constants accessed by the + # function. Note that we have to call _object_contents on each + # constants because the code object of nested functions can + # show-up among the constants. + z = [_object_contents(cc) for cc in code.co_consts if cc != docstring] + contents.extend(b',(') + contents.extend(bytearray(',', 'utf-8').join(z)) + contents.extend(b')') + + # The code contents depends on the variable names used to + # accessed global variable, as changing the variable name changes + # the variable actually accessed and therefore changes the + # function result. + z= [bytearray(_object_contents(cc)) for cc in code.co_names] + contents.extend(b',(') + contents.extend(bytearray(',','utf-8').join(z)) + contents.extend(b')') + + # The code contents depends on its actual code!!! + contents.extend(b',(') + contents.extend(code.co_code) + contents.extend(b')') + + return contents + + +def _function_contents(func): + """ + The signature is as follows (should be byte/chars): + < _code_contents (see above) from func.__code__ > + ,( comma separated _object_contents for function argument defaults) + ,( comma separated _object_contents for any closure contents ) + + + See also: https://docs.python.org/3/reference/datamodel.html + - func.__code__ - The code object representing the compiled function body. + - func.__defaults__ - A tuple containing default argument values for those arguments that have defaults, or None if no arguments have a default value + - func.__closure__ - None or a tuple of cells that contain bindings for the function's free variables. + + :Returns: + Signature contents of a function. (in bytes) + """ + + contents = [_code_contents(func.__code__, func.__doc__)] + + # The function contents depends on the value of defaults arguments + if func.__defaults__: + + function_defaults_contents = [_object_contents(cc) for cc in func.__defaults__] + + defaults = bytearray(b',(') + defaults.extend(bytearray(b',').join(function_defaults_contents)) + defaults.extend(b')') + + contents.append(defaults) + else: + contents.append(b',()') + + # The function contents depends on the closure captured cell values. + closure = func.__closure__ or [] + + try: + closure_contents = [_object_contents(x.cell_contents) for x in closure] + except AttributeError: + closure_contents = [] + + contents.append(b',(') + contents.append(bytearray(b',').join(closure_contents)) + contents.append(b')') + + retval = bytearray(b'').join(contents) + return retval + + +def _object_instance_content(obj): + """ + Returns consistant content for a action class or an instance thereof + + :Parameters: + - `obj` Should be either and action class or an instance thereof + + :Returns: + bytearray or bytes representing the obj suitable for generating a signature from. + """ + retval = bytearray() + + if obj is None: + return b'N.' + + if isinstance(obj, SCons.Util.BaseStringTypes): + return SCons.Util.to_bytes(obj) + + inst_class = obj.__class__ + inst_class_name = bytearray(obj.__class__.__name__,'utf-8') + inst_class_module = bytearray(obj.__class__.__module__,'utf-8') + inst_class_hierarchy = bytearray(repr(inspect.getclasstree([obj.__class__,])),'utf-8') + # print("ICH:%s : %s"%(inst_class_hierarchy, repr(obj))) + + properties = [(p, getattr(obj, p, "None")) for p in dir(obj) if not (p[:2] == '__' or inspect.ismethod(getattr(obj, p)) or inspect.isbuiltin(getattr(obj,p))) ] + properties.sort() + properties_str = ','.join(["%s=%s"%(p[0],p[1]) for p in properties]) + properties_bytes = bytearray(properties_str,'utf-8') + + methods = [p for p in dir(obj) if inspect.ismethod(getattr(obj, p))] + methods.sort() + + method_contents = [] + for m in methods: + # print("Method:%s"%m) + v = _function_contents(getattr(obj, m)) + # print("[%s->]V:%s [%s]"%(m,v,type(v))) + method_contents.append(v) + + retval = bytearray(b'{') + retval.extend(inst_class_name) + retval.extend(b":") + retval.extend(inst_class_module) + retval.extend(b'}[[') + retval.extend(inst_class_hierarchy) + retval.extend(b']]{{') + retval.extend(bytearray(b",").join(method_contents)) + retval.extend(b"}}{{{") + retval.extend(properties_bytes) + retval.extend(b'}}}') + return retval + + # print("class :%s"%inst_class) + # print("class_name :%s"%inst_class_name) + # print("class_module :%s"%inst_class_module) + # print("Class hier :\n%s"%pp.pformat(inst_class_hierarchy)) + # print("Inst Properties:\n%s"%pp.pformat(properties)) + # print("Inst Methods :\n%s"%pp.pformat(methods)) + +def _actionAppend(act1, act2): + # This function knows how to slap two actions together. + # Mainly, it handles ListActions by concatenating into + # a single ListAction. + a1 = Action(act1) + a2 = Action(act2) + if a1 is None: + return a2 + if a2 is None: + return a1 + if isinstance(a1, ListAction): + if isinstance(a2, ListAction): + return ListAction(a1.list + a2.list) + else: + return ListAction(a1.list + [ a2 ]) + else: + if isinstance(a2, ListAction): + return ListAction([ a1 ] + a2.list) + else: + return ListAction([ a1, a2 ]) + + +def _do_create_keywords(args, kw): + """This converts any arguments after the action argument into + their equivalent keywords and adds them to the kw argument. + """ + v = kw.get('varlist', ()) + # prevent varlist="FOO" from being interpreted as ['F', 'O', 'O'] + if is_String(v): v = (v,) + kw['varlist'] = tuple(v) + if args: + # turn positional args into equivalent keywords + cmdstrfunc = args[0] + if cmdstrfunc is None or is_String(cmdstrfunc): + kw['cmdstr'] = cmdstrfunc + elif callable(cmdstrfunc): + kw['strfunction'] = cmdstrfunc + else: + raise SCons.Errors.UserError( + 'Invalid command display variable type. ' + 'You must either pass a string or a callback which ' + 'accepts (target, source, env) as parameters.') + if len(args) > 1: + kw['varlist'] = tuple(SCons.Util.flatten(args[1:])) + kw['varlist'] + if kw.get('strfunction', _null) is not _null \ + and kw.get('cmdstr', _null) is not _null: + raise SCons.Errors.UserError( + 'Cannot have both strfunction and cmdstr args to Action()') + + +def _do_create_action(act, kw): + """This is the actual "implementation" for the + Action factory method, below. This handles the + fact that passing lists to Action() itself has + different semantics than passing lists as elements + of lists. + + The former will create a ListAction, the latter + will create a CommandAction by converting the inner + list elements to strings.""" + + if isinstance(act, ActionBase): + return act + + if is_String(act): + var=SCons.Util.get_environment_var(act) + if var: + # This looks like a string that is purely an Environment + # variable reference, like "$FOO" or "${FOO}". We do + # something special here...we lazily evaluate the contents + # of that Environment variable, so a user could put something + # like a function or a CommandGenerator in that variable + # instead of a string. + return LazyAction(var, kw) + commands = str(act).split('\n') + if len(commands) == 1: + return CommandAction(commands[0], **kw) + # The list of string commands may include a LazyAction, so we + # reprocess them via _do_create_list_action. + return _do_create_list_action(commands, kw) + + if is_List(act): + return CommandAction(act, **kw) + + if callable(act): + try: + gen = kw['generator'] + del kw['generator'] + except KeyError: + gen = 0 + if gen: + action_type = CommandGeneratorAction + else: + action_type = FunctionAction + return action_type(act, kw) + + # Catch a common error case with a nice message: + if isinstance(act, int) or isinstance(act, float): + raise TypeError("Don't know how to create an Action from a number (%s)"%act) + # Else fail silently (???) + return None + + +def _do_create_list_action(act, kw): + """A factory for list actions. Convert the input list into Actions + and then wrap them in a ListAction.""" + acts = [] + for a in act: + aa = _do_create_action(a, kw) + if aa is not None: acts.append(aa) + if not acts: + return ListAction([]) + elif len(acts) == 1: + return acts[0] + else: + return ListAction(acts) + + +def Action(act, *args, **kw): + """A factory for action objects.""" + # Really simple: the _do_create_* routines do the heavy lifting. + _do_create_keywords(args, kw) + if is_List(act): + return _do_create_list_action(act, kw) + return _do_create_action(act, kw) + + +class ActionBase(object): + """Base class for all types of action objects that can be held by + other objects (Builders, Executors, etc.) This provides the + common methods for manipulating and combining those actions.""" + + def __eq__(self, other): + return self.__dict__ == other + + def no_batch_key(self, env, target, source): + return None + + batch_key = no_batch_key + + def genstring(self, target, source, env): + return str(self) + + def get_contents(self, target, source, env): + result = self.get_presig(target, source, env) + + if not isinstance(result,(bytes, bytearray)): + result = bytearray("",'utf-8').join([ SCons.Util.to_bytes(r) for r in result ]) + else: + # Make a copy and put in bytearray, without this the contents returned by get_presig + # can be changed by the logic below, appending with each call and causing very + # hard to track down issues... + result = bytearray(result) + + # At this point everything should be a bytearray + + # This should never happen, as the Action() factory should wrap + # the varlist, but just in case an action is created directly, + # we duplicate this check here. + vl = self.get_varlist(target, source, env) + if is_String(vl): vl = (vl,) + for v in vl: + # do the subst this way to ignore $(...$) parts: + if isinstance(result, bytearray): + result.extend(SCons.Util.to_bytes(env.subst_target_source('${'+v+'}', SCons.Subst.SUBST_SIG, target, source))) + else: + raise Exception("WE SHOULD NEVER GET HERE result should be bytearray not:%s"%type(result)) + # result.append(SCons.Util.to_bytes(env.subst_target_source('${'+v+'}', SCons.Subst.SUBST_SIG, target, source))) + + + if isinstance(result, (bytes,bytearray)): + return result + else: + raise Exception("WE SHOULD NEVER GET HERE - #2 result should be bytearray not:%s" % type(result)) + # return b''.join(result) + + def __add__(self, other): + return _actionAppend(self, other) + + def __radd__(self, other): + return _actionAppend(other, self) + + def presub_lines(self, env): + # CommandGeneratorAction needs a real environment + # in order to return the proper string here, since + # it may call LazyAction, which looks up a key + # in that env. So we temporarily remember the env here, + # and CommandGeneratorAction will use this env + # when it calls its _generate method. + self.presub_env = env + lines = str(self).split('\n') + self.presub_env = None # don't need this any more + return lines + + def get_varlist(self, target, source, env, executor=None): + return self.varlist + + def get_targets(self, env, executor): + """ + Returns the type of targets ($TARGETS, $CHANGED_TARGETS) used + by this action. + """ + return self.targets + + +class _ActionAction(ActionBase): + """Base class for actions that create output objects.""" + def __init__(self, cmdstr=_null, strfunction=_null, varlist=(), + presub=_null, chdir=None, exitstatfunc=None, + batch_key=None, targets='$TARGETS', + **kw): + self.cmdstr = cmdstr + if strfunction is not _null: + if strfunction is None: + self.cmdstr = None + else: + self.strfunction = strfunction + self.varlist = varlist + self.presub = presub + self.chdir = chdir + if not exitstatfunc: + exitstatfunc = default_exitstatfunc + self.exitstatfunc = exitstatfunc + + self.targets = targets + + if batch_key: + if not callable(batch_key): + # They have set batch_key, but not to their own + # callable. The default behavior here will batch + # *all* targets+sources using this action, separated + # for each construction environment. + def default_batch_key(self, env, target, source): + return (id(self), id(env)) + batch_key = default_batch_key + SCons.Util.AddMethod(self, batch_key, 'batch_key') + + def print_cmd_line(self, s, target, source, env): + """ + In python 3, and in some of our tests, sys.stdout is + a String io object, and it takes unicode strings only + In other cases it's a regular Python 2.x file object + which takes strings (bytes), and if you pass those a + unicode object they try to decode with 'ascii' codec + which fails if the cmd line has any hi-bit-set chars. + This code assumes s is a regular string, but should + work if it's unicode too. + """ + try: + sys.stdout.write(s + u"\n") + except UnicodeDecodeError: + sys.stdout.write(s + "\n") + + def __call__(self, target, source, env, + exitstatfunc=_null, + presub=_null, + show=_null, + execute=_null, + chdir=_null, + executor=None): + if not is_List(target): + target = [target] + if not is_List(source): + source = [source] + + if presub is _null: + presub = self.presub + if presub is _null: + presub = print_actions_presub + if exitstatfunc is _null: exitstatfunc = self.exitstatfunc + if show is _null: show = print_actions + if execute is _null: execute = execute_actions + if chdir is _null: chdir = self.chdir + save_cwd = None + if chdir: + save_cwd = os.getcwd() + try: + chdir = str(chdir.get_abspath()) + except AttributeError: + if not is_String(chdir): + if executor: + chdir = str(executor.batches[0].targets[0].dir) + else: + chdir = str(target[0].dir) + if presub: + if executor: + target = executor.get_all_targets() + source = executor.get_all_sources() + t = ' and '.join(map(str, target)) + l = '\n '.join(self.presub_lines(env)) + out = u"Building %s with action:\n %s\n" % (t, l) + sys.stdout.write(out) + cmd = None + if show and self.strfunction: + if executor: + target = executor.get_all_targets() + source = executor.get_all_sources() + try: + cmd = self.strfunction(target, source, env, executor) + except TypeError: + cmd = self.strfunction(target, source, env) + if cmd: + if chdir: + cmd = ('os.chdir(%s)\n' % repr(chdir)) + cmd + try: + get = env.get + except AttributeError: + print_func = self.print_cmd_line + else: + print_func = get('PRINT_CMD_LINE_FUNC') + if not print_func: + print_func = self.print_cmd_line + print_func(cmd, target, source, env) + stat = 0 + if execute: + if chdir: + os.chdir(chdir) + try: + stat = self.execute(target, source, env, executor=executor) + if isinstance(stat, SCons.Errors.BuildError): + s = exitstatfunc(stat.status) + if s: + stat.status = s + else: + stat = s + else: + stat = exitstatfunc(stat) + finally: + if save_cwd: + os.chdir(save_cwd) + if cmd and save_cwd: + print_func('os.chdir(%s)' % repr(save_cwd), target, source, env) + + return stat + + +def _string_from_cmd_list(cmd_list): + """Takes a list of command line arguments and returns a pretty + representation for printing.""" + cl = [] + for arg in map(str, cmd_list): + if ' ' in arg or '\t' in arg: + arg = '"' + arg + '"' + cl.append(arg) + return ' '.join(cl) + +default_ENV = None + + +def get_default_ENV(env): + """ + A fiddlin' little function that has an 'import SCons.Environment' which + can't be moved to the top level without creating an import loop. Since + this import creates a local variable named 'SCons', it blocks access to + the global variable, so we move it here to prevent complaints about local + variables being used uninitialized. + """ + global default_ENV + try: + return env['ENV'] + except KeyError: + if not default_ENV: + import SCons.Environment + # This is a hideously expensive way to get a default shell + # environment. What it really should do is run the platform + # setup to get the default ENV. Fortunately, it's incredibly + # rare for an Environment not to have a shell environment, so + # we're not going to worry about it overmuch. + default_ENV = SCons.Environment.Environment()['ENV'] + return default_ENV + + +def _subproc(scons_env, cmd, error = 'ignore', **kw): + """Do common setup for a subprocess.Popen() call + + This function is still in draft mode. We're going to need something like + it in the long run as more and more places use subprocess, but I'm sure + it'll have to be tweaked to get the full desired functionality. + one special arg (so far?), 'error', to tell what to do with exceptions. + """ + # allow std{in,out,err} to be "'devnull'" + io = kw.get('stdin') + if is_String(io) and io == 'devnull': + kw['stdin'] = open(os.devnull) + io = kw.get('stdout') + if is_String(io) and io == 'devnull': + kw['stdout'] = open(os.devnull, 'w') + io = kw.get('stderr') + if is_String(io) and io == 'devnull': + kw['stderr'] = open(os.devnull, 'w') + + # Figure out what shell environment to use + ENV = kw.get('env', None) + if ENV is None: ENV = get_default_ENV(scons_env) + + # Ensure that the ENV values are all strings: + new_env = {} + for key, value in ENV.items(): + if is_List(value): + # If the value is a list, then we assume it is a path list, + # because that's a pretty common list-like value to stick + # in an environment variable: + value = SCons.Util.flatten_sequence(value) + new_env[key] = os.pathsep.join(map(str, value)) + else: + # It's either a string or something else. If it's a string, + # we still want to call str() because it might be a *Unicode* + # string, which makes subprocess.Popen() gag. If it isn't a + # string or a list, then we just coerce it to a string, which + # is the proper way to handle Dir and File instances and will + # produce something reasonable for just about everything else: + new_env[key] = str(value) + kw['env'] = new_env + + try: + pobj = subprocess.Popen(cmd, **kw) + except EnvironmentError as e: + if error == 'raise': raise + # return a dummy Popen instance that only returns error + class dummyPopen(object): + def __init__(self, e): self.exception = e + def communicate(self, input=None): return ('', '') + def wait(self): return -self.exception.errno + stdin = None + class f(object): + def read(self): return '' + def readline(self): return '' + def __iter__(self): return iter(()) + stdout = stderr = f() + pobj = dummyPopen(e) + finally: + # clean up open file handles stored in parent's kw + for k, v in kw.items(): + if hasattr(v, 'close'): + v.close() + return pobj + + +class CommandAction(_ActionAction): + """Class for command-execution actions.""" + def __init__(self, cmd, **kw): + # Cmd can actually be a list or a single item; if it's a + # single item it should be the command string to execute; if a + # list then it should be the words of the command string to + # execute. Only a single command should be executed by this + # object; lists of commands should be handled by embedding + # these objects in a ListAction object (which the Action() + # factory above does). cmd will be passed to + # Environment.subst_list() for substituting environment + # variables. + if SCons.Debug.track_instances: logInstanceCreation(self, 'Action.CommandAction') + + _ActionAction.__init__(self, **kw) + if is_List(cmd): + if [c for c in cmd if is_List(c)]: + raise TypeError("CommandAction should be given only " + "a single command") + self.cmd_list = cmd + + def __str__(self): + if is_List(self.cmd_list): + return ' '.join(map(str, self.cmd_list)) + return str(self.cmd_list) + + def process(self, target, source, env, executor=None): + if executor: + result = env.subst_list(self.cmd_list, 0, executor=executor) + else: + result = env.subst_list(self.cmd_list, 0, target, source) + silent = None + ignore = None + while True: + try: c = result[0][0][0] + except IndexError: c = None + if c == '@': silent = 1 + elif c == '-': ignore = 1 + else: break + result[0][0] = result[0][0][1:] + try: + if not result[0][0]: + result[0] = result[0][1:] + except IndexError: + pass + return result, ignore, silent + + def strfunction(self, target, source, env, executor=None): + if self.cmdstr is None: + return None + if self.cmdstr is not _null: + from SCons.Subst import SUBST_RAW + if executor: + c = env.subst(self.cmdstr, SUBST_RAW, executor=executor) + else: + c = env.subst(self.cmdstr, SUBST_RAW, target, source) + if c: + return c + cmd_list, ignore, silent = self.process(target, source, env, executor) + if silent: + return '' + return _string_from_cmd_list(cmd_list[0]) + + def execute(self, target, source, env, executor=None): + """Execute a command action. + + This will handle lists of commands as well as individual commands, + because construction variable substitution may turn a single + "command" into a list. This means that this class can actually + handle lists of commands, even though that's not how we use it + externally. + """ + escape_list = SCons.Subst.escape_list + flatten_sequence = SCons.Util.flatten_sequence + + try: + shell = env['SHELL'] + except KeyError: + raise SCons.Errors.UserError('Missing SHELL construction variable.') + + try: + spawn = env['SPAWN'] + except KeyError: + raise SCons.Errors.UserError('Missing SPAWN construction variable.') + else: + if is_String(spawn): + spawn = env.subst(spawn, raw=1, conv=lambda x: x) + + escape = env.get('ESCAPE', lambda x: x) + + ENV = get_default_ENV(env) + + # Ensure that the ENV values are all strings: + for key, value in ENV.items(): + if not is_String(value): + if is_List(value): + # If the value is a list, then we assume it is a + # path list, because that's a pretty common list-like + # value to stick in an environment variable: + value = flatten_sequence(value) + ENV[key] = os.pathsep.join(map(str, value)) + else: + # If it isn't a string or a list, then we just coerce + # it to a string, which is the proper way to handle + # Dir and File instances and will produce something + # reasonable for just about everything else: + ENV[key] = str(value) + + if executor: + target = executor.get_all_targets() + source = executor.get_all_sources() + cmd_list, ignore, silent = self.process(target, list(map(rfile, source)), env, executor) + + # Use len() to filter out any "command" that's zero-length. + for cmd_line in filter(len, cmd_list): + # Escape the command line for the interpreter we are using. + cmd_line = escape_list(cmd_line, escape) + result = spawn(shell, escape, cmd_line[0], cmd_line, ENV) + if not ignore and result: + msg = "Error %s" % result + return SCons.Errors.BuildError(errstr=msg, + status=result, + action=self, + command=cmd_line) + return 0 + + def get_presig(self, target, source, env, executor=None): + """Return the signature contents of this action's command line. + + This strips $(-$) and everything in between the string, + since those parts don't affect signatures. + """ + from SCons.Subst import SUBST_SIG + cmd = self.cmd_list + if is_List(cmd): + cmd = ' '.join(map(str, cmd)) + else: + cmd = str(cmd) + if executor: + return env.subst_target_source(cmd, SUBST_SIG, executor=executor) + else: + return env.subst_target_source(cmd, SUBST_SIG, target, source) + + def get_implicit_deps(self, target, source, env, executor=None): + icd = env.get('IMPLICIT_COMMAND_DEPENDENCIES', True) + if is_String(icd) and icd[:1] == '$': + icd = env.subst(icd) + if not icd or icd in ('0', 'None'): + return [] + from SCons.Subst import SUBST_SIG + if executor: + cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, executor=executor) + else: + cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, target, source) + res = [] + for cmd_line in cmd_list: + if cmd_line: + d = str(cmd_line[0]) + m = strip_quotes.match(d) + if m: + d = m.group(1) + d = env.WhereIs(d) + if d: + res.append(env.fs.File(d)) + return res + + +class CommandGeneratorAction(ActionBase): + """Class for command-generator actions.""" + def __init__(self, generator, kw): + if SCons.Debug.track_instances: logInstanceCreation(self, 'Action.CommandGeneratorAction') + self.generator = generator + self.gen_kw = kw + self.varlist = kw.get('varlist', ()) + self.targets = kw.get('targets', '$TARGETS') + + def _generate(self, target, source, env, for_signature, executor=None): + # ensure that target is a list, to make it easier to write + # generator functions: + if not is_List(target): + target = [target] + + if executor: + target = executor.get_all_targets() + source = executor.get_all_sources() + ret = self.generator(target=target, + source=source, + env=env, + for_signature=for_signature) + gen_cmd = Action(ret, **self.gen_kw) + if not gen_cmd: + raise SCons.Errors.UserError("Object returned from command generator: %s cannot be used to create an Action." % repr(ret)) + return gen_cmd + + def __str__(self): + try: + env = self.presub_env + except AttributeError: + env = None + if env is None: + env = SCons.Defaults.DefaultEnvironment() + act = self._generate([], [], env, 1) + return str(act) + + def batch_key(self, env, target, source): + return self._generate(target, source, env, 1).batch_key(env, target, source) + + def genstring(self, target, source, env, executor=None): + return self._generate(target, source, env, 1, executor).genstring(target, source, env) + + def __call__(self, target, source, env, exitstatfunc=_null, presub=_null, + show=_null, execute=_null, chdir=_null, executor=None): + act = self._generate(target, source, env, 0, executor) + if act is None: + raise SCons.Errors.UserError("While building `%s': " + "Cannot deduce file extension from source files: %s" + % (repr(list(map(str, target))), repr(list(map(str, source))))) + return act(target, source, env, exitstatfunc, presub, + show, execute, chdir, executor) + + def get_presig(self, target, source, env, executor=None): + """Return the signature contents of this action's command line. + + This strips $(-$) and everything in between the string, + since those parts don't affect signatures. + """ + return self._generate(target, source, env, 1, executor).get_presig(target, source, env) + + def get_implicit_deps(self, target, source, env, executor=None): + return self._generate(target, source, env, 1, executor).get_implicit_deps(target, source, env) + + def get_varlist(self, target, source, env, executor=None): + return self._generate(target, source, env, 1, executor).get_varlist(target, source, env, executor) + + def get_targets(self, env, executor): + return self._generate(None, None, env, 1, executor).get_targets(env, executor) + + +class LazyAction(CommandGeneratorAction, CommandAction): + """ + A LazyAction is a kind of hybrid generator and command action for + strings of the form "$VAR". These strings normally expand to other + strings (think "$CCCOM" to "$CC -c -o $TARGET $SOURCE"), but we also + want to be able to replace them with functions in the construction + environment. Consequently, we want lazy evaluation and creation of + an Action in the case of the function, but that's overkill in the more + normal case of expansion to other strings. + + So we do this with a subclass that's both a generator *and* + a command action. The overridden methods all do a quick check + of the construction variable, and if it's a string we just call + the corresponding CommandAction method to do the heavy lifting. + If not, then we call the same-named CommandGeneratorAction method. + The CommandGeneratorAction methods work by using the overridden + _generate() method, that is, our own way of handling "generation" of + an action based on what's in the construction variable. + """ + + def __init__(self, var, kw): + if SCons.Debug.track_instances: logInstanceCreation(self, 'Action.LazyAction') + CommandAction.__init__(self, '${'+var+'}', **kw) + self.var = SCons.Util.to_String(var) + self.gen_kw = kw + + def get_parent_class(self, env): + c = env.get(self.var) + if is_String(c) and not '\n' in c: + return CommandAction + return CommandGeneratorAction + + def _generate_cache(self, env): + if env: + c = env.get(self.var, '') + else: + c = '' + gen_cmd = Action(c, **self.gen_kw) + if not gen_cmd: + raise SCons.Errors.UserError("$%s value %s cannot be used to create an Action." % (self.var, repr(c))) + return gen_cmd + + def _generate(self, target, source, env, for_signature, executor=None): + return self._generate_cache(env) + + def __call__(self, target, source, env, *args, **kw): + c = self.get_parent_class(env) + return c.__call__(self, target, source, env, *args, **kw) + + def get_presig(self, target, source, env): + c = self.get_parent_class(env) + return c.get_presig(self, target, source, env) + + def get_varlist(self, target, source, env, executor=None): + c = self.get_parent_class(env) + return c.get_varlist(self, target, source, env, executor) + + +class FunctionAction(_ActionAction): + """Class for Python function actions.""" + + def __init__(self, execfunction, kw): + if SCons.Debug.track_instances: logInstanceCreation(self, 'Action.FunctionAction') + + self.execfunction = execfunction + try: + self.funccontents = _callable_contents(execfunction) + except AttributeError: + try: + # See if execfunction will do the heavy lifting for us. + self.gc = execfunction.get_contents + except AttributeError: + # This is weird, just do the best we can. + self.funccontents = _object_contents(execfunction) + + _ActionAction.__init__(self, **kw) + + def function_name(self): + try: + return self.execfunction.__name__ + except AttributeError: + try: + return self.execfunction.__class__.__name__ + except AttributeError: + return "unknown_python_function" + + def strfunction(self, target, source, env, executor=None): + if self.cmdstr is None: + return None + if self.cmdstr is not _null: + from SCons.Subst import SUBST_RAW + if executor: + c = env.subst(self.cmdstr, SUBST_RAW, executor=executor) + else: + c = env.subst(self.cmdstr, SUBST_RAW, target, source) + if c: + return c + + def array(a): + def quote(s): + try: + str_for_display = s.str_for_display + except AttributeError: + s = repr(s) + else: + s = str_for_display() + return s + return '[' + ", ".join(map(quote, a)) + ']' + try: + strfunc = self.execfunction.strfunction + except AttributeError: + pass + else: + if strfunc is None: + return None + if callable(strfunc): + return strfunc(target, source, env) + name = self.function_name() + tstr = array(target) + sstr = array(source) + return "%s(%s, %s)" % (name, tstr, sstr) + + def __str__(self): + name = self.function_name() + if name == 'ActionCaller': + return str(self.execfunction) + return "%s(target, source, env)" % name + + def execute(self, target, source, env, executor=None): + exc_info = (None,None,None) + try: + if executor: + target = executor.get_all_targets() + source = executor.get_all_sources() + rsources = list(map(rfile, source)) + try: + result = self.execfunction(target=target, source=rsources, env=env) + except KeyboardInterrupt as e: + raise + except SystemExit as e: + raise + except Exception as e: + result = e + exc_info = sys.exc_info() + + if result: + result = SCons.Errors.convert_to_BuildError(result, exc_info) + result.node=target + result.action=self + try: + result.command=self.strfunction(target, source, env, executor) + except TypeError: + result.command=self.strfunction(target, source, env) + + # FIXME: This maintains backward compatibility with respect to + # which type of exceptions were returned by raising an + # exception and which ones were returned by value. It would + # probably be best to always return them by value here, but + # some codes do not check the return value of Actions and I do + # not have the time to modify them at this point. + if (exc_info[1] and + not isinstance(exc_info[1],EnvironmentError)): + raise result + + return result + finally: + # Break the cycle between the traceback object and this + # function stack frame. See the sys.exc_info() doc info for + # more information about this issue. + del exc_info + + def get_presig(self, target, source, env): + """Return the signature contents of this callable action.""" + try: + return self.gc(target, source, env) + except AttributeError: + return self.funccontents + + def get_implicit_deps(self, target, source, env): + return [] + +class ListAction(ActionBase): + """Class for lists of other actions.""" + def __init__(self, actionlist): + if SCons.Debug.track_instances: logInstanceCreation(self, 'Action.ListAction') + def list_of_actions(x): + if isinstance(x, ActionBase): + return x + return Action(x) + self.list = list(map(list_of_actions, actionlist)) + # our children will have had any varlist + # applied; we don't need to do it again + self.varlist = () + self.targets = '$TARGETS' + + def genstring(self, target, source, env): + return '\n'.join([a.genstring(target, source, env) for a in self.list]) + + def __str__(self): + return '\n'.join(map(str, self.list)) + + def presub_lines(self, env): + return SCons.Util.flatten_sequence( + [a.presub_lines(env) for a in self.list]) + + def get_presig(self, target, source, env): + """Return the signature contents of this action list. + + Simple concatenation of the signatures of the elements. + """ + return b"".join([bytes(x.get_contents(target, source, env)) for x in self.list]) + + def __call__(self, target, source, env, exitstatfunc=_null, presub=_null, + show=_null, execute=_null, chdir=_null, executor=None): + if executor: + target = executor.get_all_targets() + source = executor.get_all_sources() + for act in self.list: + stat = act(target, source, env, exitstatfunc, presub, + show, execute, chdir, executor) + if stat: + return stat + return 0 + + def get_implicit_deps(self, target, source, env): + result = [] + for act in self.list: + result.extend(act.get_implicit_deps(target, source, env)) + return result + + def get_varlist(self, target, source, env, executor=None): + result = OrderedDict() + for act in self.list: + for var in act.get_varlist(target, source, env, executor): + result[var] = True + return list(result.keys()) + + +class ActionCaller(object): + """A class for delaying calling an Action function with specific + (positional and keyword) arguments until the Action is actually + executed. + + This class looks to the rest of the world like a normal Action object, + but what it's really doing is hanging on to the arguments until we + have a target, source and env to use for the expansion. + """ + def __init__(self, parent, args, kw): + self.parent = parent + self.args = args + self.kw = kw + + def get_contents(self, target, source, env): + actfunc = self.parent.actfunc + try: + # "self.actfunc" is a function. + contents = actfunc.__code__.co_code + except AttributeError: + # "self.actfunc" is a callable object. + try: + contents = actfunc.__call__.__func__.__code__.co_code + except AttributeError: + # No __call__() method, so it might be a builtin + # or something like that. Do the best we can. + contents = repr(actfunc) + + return contents + + def subst(self, s, target, source, env): + # If s is a list, recursively apply subst() + # to every element in the list + if is_List(s): + result = [] + for elem in s: + result.append(self.subst(elem, target, source, env)) + return self.parent.convert(result) + + # Special-case hack: Let a custom function wrapped in an + # ActionCaller get at the environment through which the action + # was called by using this hard-coded value as a special return. + if s == '$__env__': + return env + elif is_String(s): + return env.subst(s, 1, target, source) + return self.parent.convert(s) + + def subst_args(self, target, source, env): + return [self.subst(x, target, source, env) for x in self.args] + + def subst_kw(self, target, source, env): + kw = {} + for key in list(self.kw.keys()): + kw[key] = self.subst(self.kw[key], target, source, env) + return kw + + def __call__(self, target, source, env, executor=None): + args = self.subst_args(target, source, env) + kw = self.subst_kw(target, source, env) + return self.parent.actfunc(*args, **kw) + + def strfunction(self, target, source, env): + args = self.subst_args(target, source, env) + kw = self.subst_kw(target, source, env) + return self.parent.strfunc(*args, **kw) + + def __str__(self): + return self.parent.strfunc(*self.args, **self.kw) + + +class ActionFactory(object): + """A factory class that will wrap up an arbitrary function + as an SCons-executable Action object. + + The real heavy lifting here is done by the ActionCaller class. + We just collect the (positional and keyword) arguments that we're + called with and give them to the ActionCaller object we create, + so it can hang onto them until it needs them. + """ + def __init__(self, actfunc, strfunc, convert=lambda x: x): + self.actfunc = actfunc + self.strfunc = strfunc + self.convert = convert + + def __call__(self, *args, **kw): + ac = ActionCaller(self, args, kw) + action = Action(ac, strfunction=ac.strfunction) + return action + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Builder.py b/tools/scons/scons-local-3.0.5/SCons/Builder.py new file mode 100755 index 0000000000..2d337c9158 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Builder.py @@ -0,0 +1,888 @@ +""" +SCons.Builder + +Builder object subsystem. + +A Builder object is a callable that encapsulates information about how +to execute actions to create a target Node (file) from source Nodes +(files), and how to create those dependencies for tracking. + +The main entry point here is the Builder() factory method. This provides +a procedural interface that creates the right underlying Builder object +based on the keyword arguments supplied and the types of the arguments. + +The goal is for this external interface to be simple enough that the +vast majority of users can create new Builders as necessary to support +building new types of files in their configurations, without having to +dive any deeper into this subsystem. + +The base class here is BuilderBase. This is a concrete base class which +does, in fact, represent the Builder objects that we (or users) create. + +There is also a proxy that looks like a Builder: + + CompositeBuilder + + This proxies for a Builder with an action that is actually a + dictionary that knows how to map file suffixes to a specific + action. This is so that we can invoke different actions + (compilers, compile options) for different flavors of source + files. + +Builders and their proxies have the following public interface methods +used by other modules: + + - __call__() + THE public interface. Calling a Builder object (with the + use of internal helper methods) sets up the target and source + dependencies, appropriate mapping to a specific action, and the + environment manipulation necessary for overridden construction + variable. This also takes care of warning about possible mistakes + in keyword arguments. + + - add_emitter() + Adds an emitter for a specific file suffix, used by some Tool + modules to specify that (for example) a yacc invocation on a .y + can create a .h *and* a .c file. + + - add_action() + Adds an action for a specific file suffix, heavily used by + Tool modules to add their specific action(s) for turning + a source file into an object file to the global static + and shared object file Builders. + +There are the following methods for internal use within this module: + + - _execute() + The internal method that handles the heavily lifting when a + Builder is called. This is used so that the __call__() methods + can set up warning about possible mistakes in keyword-argument + overrides, and *then* execute all of the steps necessary so that + the warnings only occur once. + + - get_name() + Returns the Builder's name within a specific Environment, + primarily used to try to return helpful information in error + messages. + + - adjust_suffix() + - get_prefix() + - get_suffix() + - get_src_suffix() + - set_src_suffix() + Miscellaneous stuff for handling the prefix and suffix + manipulation we use in turning source file names into target + file names. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +__revision__ = "src/engine/SCons/Builder.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import collections + +import SCons.Action +import SCons.Debug +from SCons.Debug import logInstanceCreation +from SCons.Errors import InternalError, UserError +import SCons.Executor +import SCons.Memoize +import SCons.Util +import SCons.Warnings + +class _Null(object): + pass + +_null = _Null + +def match_splitext(path, suffixes = []): + if suffixes: + matchsuf = [S for S in suffixes if path[-len(S):] == S] + if matchsuf: + suf = max([(len(_f),_f) for _f in matchsuf])[1] + return [path[:-len(suf)], path[-len(suf):]] + return SCons.Util.splitext(path) + +class DictCmdGenerator(SCons.Util.Selector): + """This is a callable class that can be used as a + command generator function. It holds on to a dictionary + mapping file suffixes to Actions. It uses that dictionary + to return the proper action based on the file suffix of + the source file.""" + + def __init__(self, dict=None, source_ext_match=1): + SCons.Util.Selector.__init__(self, dict) + self.source_ext_match = source_ext_match + + def src_suffixes(self): + return list(self.keys()) + + def add_action(self, suffix, action): + """Add a suffix-action pair to the mapping. + """ + self[suffix] = action + + def __call__(self, target, source, env, for_signature): + if not source: + return [] + + if self.source_ext_match: + suffixes = self.src_suffixes() + ext = None + for src in map(str, source): + my_ext = match_splitext(src, suffixes)[1] + if ext and my_ext != ext: + raise UserError("While building `%s' from `%s': Cannot build multiple sources with different extensions: %s, %s" + % (repr(list(map(str, target))), src, ext, my_ext)) + ext = my_ext + else: + ext = match_splitext(str(source[0]), self.src_suffixes())[1] + + if not ext: + #return ext + raise UserError("While building `%s': " + "Cannot deduce file extension from source files: %s" + % (repr(list(map(str, target))), repr(list(map(str, source))))) + + try: + ret = SCons.Util.Selector.__call__(self, env, source, ext) + except KeyError as e: + raise UserError("Ambiguous suffixes after environment substitution: %s == %s == %s" % (e.args[0], e.args[1], e.args[2])) + if ret is None: + raise UserError("While building `%s' from `%s': Don't know how to build from a source file with suffix `%s'. Expected a suffix in this list: %s." % \ + (repr(list(map(str, target))), repr(list(map(str, source))), ext, repr(list(self.keys())))) + return ret + +class CallableSelector(SCons.Util.Selector): + """A callable dictionary that will, in turn, call the value it + finds if it can.""" + def __call__(self, env, source): + value = SCons.Util.Selector.__call__(self, env, source) + if callable(value): + value = value(env, source) + return value + +class DictEmitter(SCons.Util.Selector): + """A callable dictionary that maps file suffixes to emitters. + When called, it finds the right emitter in its dictionary for the + suffix of the first source file, and calls that emitter to get the + right lists of targets and sources to return. If there's no emitter + for the suffix in its dictionary, the original target and source are + returned. + """ + def __call__(self, target, source, env): + emitter = SCons.Util.Selector.__call__(self, env, source) + if emitter: + target, source = emitter(target, source, env) + return (target, source) + +class ListEmitter(collections.UserList): + """A callable list of emitters that calls each in sequence, + returning the result. + """ + def __call__(self, target, source, env): + for e in self.data: + target, source = e(target, source, env) + return (target, source) + +# These are a common errors when calling a Builder; +# they are similar to the 'target' and 'source' keyword args to builders, +# so we issue warnings when we see them. The warnings can, of course, +# be disabled. +misleading_keywords = { + 'targets' : 'target', + 'sources' : 'source', +} + +class OverrideWarner(collections.UserDict): + """A class for warning about keyword arguments that we use as + overrides in a Builder call. + + This class exists to handle the fact that a single Builder call + can actually invoke multiple builders. This class only emits the + warnings once, no matter how many Builders are invoked. + """ + def __init__(self, dict): + collections.UserDict.__init__(self, dict) + if SCons.Debug.track_instances: logInstanceCreation(self, 'Builder.OverrideWarner') + self.already_warned = None + def warn(self): + if self.already_warned: + return + for k in list(self.keys()): + if k in misleading_keywords: + alt = misleading_keywords[k] + msg = "Did you mean to use `%s' instead of `%s'?" % (alt, k) + SCons.Warnings.warn(SCons.Warnings.MisleadingKeywordsWarning, msg) + self.already_warned = 1 + +def Builder(**kw): + """A factory for builder objects.""" + composite = None + if 'generator' in kw: + if 'action' in kw: + raise UserError("You must not specify both an action and a generator.") + kw['action'] = SCons.Action.CommandGeneratorAction(kw['generator'], {}) + del kw['generator'] + elif 'action' in kw: + source_ext_match = kw.get('source_ext_match', 1) + if 'source_ext_match' in kw: + del kw['source_ext_match'] + if SCons.Util.is_Dict(kw['action']): + composite = DictCmdGenerator(kw['action'], source_ext_match) + kw['action'] = SCons.Action.CommandGeneratorAction(composite, {}) + kw['src_suffix'] = composite.src_suffixes() + else: + kw['action'] = SCons.Action.Action(kw['action']) + + if 'emitter' in kw: + emitter = kw['emitter'] + if SCons.Util.is_String(emitter): + # This allows users to pass in an Environment + # variable reference (like "$FOO") as an emitter. + # We will look in that Environment variable for + # a callable to use as the actual emitter. + var = SCons.Util.get_environment_var(emitter) + if not var: + raise UserError("Supplied emitter '%s' does not appear to refer to an Environment variable" % emitter) + kw['emitter'] = EmitterProxy(var) + elif SCons.Util.is_Dict(emitter): + kw['emitter'] = DictEmitter(emitter) + elif SCons.Util.is_List(emitter): + kw['emitter'] = ListEmitter(emitter) + + result = BuilderBase(**kw) + + if not composite is None: + result = CompositeBuilder(result, composite) + + return result + +def _node_errors(builder, env, tlist, slist): + """Validate that the lists of target and source nodes are + legal for this builder and environment. Raise errors or + issue warnings as appropriate. + """ + + # First, figure out if there are any errors in the way the targets + # were specified. + for t in tlist: + if t.side_effect: + raise UserError("Multiple ways to build the same target were specified for: %s" % t) + if t.has_explicit_builder(): + # Check for errors when the environments are different + # No error if environments are the same Environment instance + if (not t.env is None and not t.env is env and + # Check OverrideEnvironment case - no error if wrapped Environments + # are the same instance, and overrides lists match + not (getattr(t.env, '__subject', 0) is getattr(env, '__subject', 1) and + getattr(t.env, 'overrides', 0) == getattr(env, 'overrides', 1) and + not builder.multi)): + action = t.builder.action + t_contents = t.builder.action.get_contents(tlist, slist, t.env) + contents = builder.action.get_contents(tlist, slist, env) + + if t_contents == contents: + msg = "Two different environments were specified for target %s,\n\tbut they appear to have the same action: %s" % (t, action.genstring(tlist, slist, t.env)) + SCons.Warnings.warn(SCons.Warnings.DuplicateEnvironmentWarning, msg) + else: + try: + msg = "Two environments with different actions were specified for the same target: %s\n(action 1: %s)\n(action 2: %s)" % (t,t_contents.decode('utf-8'),contents.decode('utf-8')) + except UnicodeDecodeError as e: + msg = "Two environments with different actions were specified for the same target: %s"%t + raise UserError(msg) + if builder.multi: + if t.builder != builder: + msg = "Two different builders (%s and %s) were specified for the same target: %s" % (t.builder.get_name(env), builder.get_name(env), t) + raise UserError(msg) + # TODO(batch): list constructed each time! + if t.get_executor().get_all_targets() != tlist: + msg = "Two different target lists have a target in common: %s (from %s and from %s)" % (t, list(map(str, t.get_executor().get_all_targets())), list(map(str, tlist))) + raise UserError(msg) + elif t.sources != slist: + msg = "Multiple ways to build the same target were specified for: %s (from %s and from %s)" % (t, list(map(str, t.sources)), list(map(str, slist))) + raise UserError(msg) + + if builder.single_source: + if len(slist) > 1: + raise UserError("More than one source given for single-source builder: targets=%s sources=%s" % (list(map(str,tlist)), list(map(str,slist)))) + +class EmitterProxy(object): + """This is a callable class that can act as a + Builder emitter. It holds on to a string that + is a key into an Environment dictionary, and will + look there at actual build time to see if it holds + a callable. If so, we will call that as the actual + emitter.""" + def __init__(self, var): + self.var = SCons.Util.to_String(var) + + def __call__(self, target, source, env): + emitter = self.var + + # Recursively substitute the variable. + # We can't use env.subst() because it deals only + # in strings. Maybe we should change that? + while SCons.Util.is_String(emitter) and emitter in env: + emitter = env[emitter] + if callable(emitter): + target, source = emitter(target, source, env) + elif SCons.Util.is_List(emitter): + for e in emitter: + target, source = e(target, source, env) + + return (target, source) + + + def __eq__(self, other): + return self.var == other.var + + def __lt__(self, other): + return self.var < other.var + +class BuilderBase(object): + """Base class for Builders, objects that create output + nodes (files) from input nodes (files). + """ + + def __init__(self, action = None, + prefix = '', + suffix = '', + src_suffix = '', + target_factory = None, + source_factory = None, + target_scanner = None, + source_scanner = None, + emitter = None, + multi = 0, + env = None, + single_source = 0, + name = None, + chdir = _null, + is_explicit = 1, + src_builder = None, + ensure_suffix = False, + **overrides): + if SCons.Debug.track_instances: logInstanceCreation(self, 'Builder.BuilderBase') + self._memo = {} + self.action = action + self.multi = multi + if SCons.Util.is_Dict(prefix): + prefix = CallableSelector(prefix) + self.prefix = prefix + if SCons.Util.is_Dict(suffix): + suffix = CallableSelector(suffix) + self.env = env + self.single_source = single_source + if 'overrides' in overrides: + SCons.Warnings.warn(SCons.Warnings.DeprecatedBuilderKeywordsWarning, + "The \"overrides\" keyword to Builder() creation has been deprecated;\n" +\ + "\tspecify the items as keyword arguments to the Builder() call instead.") + overrides.update(overrides['overrides']) + del overrides['overrides'] + if 'scanner' in overrides: + SCons.Warnings.warn(SCons.Warnings.DeprecatedBuilderKeywordsWarning, + "The \"scanner\" keyword to Builder() creation has been deprecated;\n" + "\tuse: source_scanner or target_scanner as appropriate.") + del overrides['scanner'] + self.overrides = overrides + + self.set_suffix(suffix) + self.set_src_suffix(src_suffix) + self.ensure_suffix = ensure_suffix + + self.target_factory = target_factory + self.source_factory = source_factory + self.target_scanner = target_scanner + self.source_scanner = source_scanner + + self.emitter = emitter + + # Optional Builder name should only be used for Builders + # that don't get attached to construction environments. + if name: + self.name = name + self.executor_kw = {} + if not chdir is _null: + self.executor_kw['chdir'] = chdir + self.is_explicit = is_explicit + + if src_builder is None: + src_builder = [] + elif not SCons.Util.is_List(src_builder): + src_builder = [ src_builder ] + self.src_builder = src_builder + + def __nonzero__(self): + raise InternalError("Do not test for the Node.builder attribute directly; use Node.has_builder() instead") + + def __bool__(self): + return self.__nonzero__() + + def get_name(self, env): + """Attempts to get the name of the Builder. + + Look at the BUILDERS variable of env, expecting it to be a + dictionary containing this Builder, and return the key of the + dictionary. If there's no key, then return a directly-configured + name (if there is one) or the name of the class (by default).""" + + try: + index = list(env['BUILDERS'].values()).index(self) + return list(env['BUILDERS'].keys())[index] + except (AttributeError, KeyError, TypeError, ValueError): + try: + return self.name + except AttributeError: + return str(self.__class__) + + def __eq__(self, other): + return self.__dict__ == other.__dict__ + + def splitext(self, path, env=None): + if not env: + env = self.env + if env: + suffixes = self.src_suffixes(env) + else: + suffixes = [] + return match_splitext(path, suffixes) + + def _adjustixes(self, files, pre, suf, ensure_suffix=False): + if not files: + return [] + result = [] + if not SCons.Util.is_List(files): + files = [files] + + for f in files: + if SCons.Util.is_String(f): + f = SCons.Util.adjustixes(f, pre, suf, ensure_suffix) + result.append(f) + return result + + def _create_nodes(self, env, target = None, source = None): + """Create and return lists of target and source nodes. + """ + src_suf = self.get_src_suffix(env) + + target_factory = env.get_factory(self.target_factory) + source_factory = env.get_factory(self.source_factory) + + source = self._adjustixes(source, None, src_suf) + slist = env.arg2nodes(source, source_factory) + + pre = self.get_prefix(env, slist) + suf = self.get_suffix(env, slist) + + if target is None: + try: + t_from_s = slist[0].target_from_source + except AttributeError: + raise UserError("Do not know how to create a target from source `%s'" % slist[0]) + except IndexError: + tlist = [] + else: + splitext = lambda S: self.splitext(S,env) + tlist = [ t_from_s(pre, suf, splitext) ] + else: + target = self._adjustixes(target, pre, suf, self.ensure_suffix) + tlist = env.arg2nodes(target, target_factory, target=target, source=source) + + if self.emitter: + # The emitter is going to do str(node), but because we're + # being called *from* a builder invocation, the new targets + # don't yet have a builder set on them and will look like + # source files. Fool the emitter's str() calls by setting + # up a temporary builder on the new targets. + new_targets = [] + for t in tlist: + if not t.is_derived(): + t.builder_set(self) + new_targets.append(t) + + orig_tlist = tlist[:] + orig_slist = slist[:] + + target, source = self.emitter(target=tlist, source=slist, env=env) + + # Now delete the temporary builders that we attached to any + # new targets, so that _node_errors() doesn't do weird stuff + # to them because it thinks they already have builders. + for t in new_targets: + if t.builder is self: + # Only delete the temporary builder if the emitter + # didn't change it on us. + t.builder_set(None) + + # Have to call arg2nodes yet again, since it is legal for + # emitters to spit out strings as well as Node instances. + tlist = env.arg2nodes(target, target_factory, + target=orig_tlist, source=orig_slist) + slist = env.arg2nodes(source, source_factory, + target=orig_tlist, source=orig_slist) + + return tlist, slist + + def _execute(self, env, target, source, overwarn={}, executor_kw={}): + # We now assume that target and source are lists or None. + if self.src_builder: + source = self.src_builder_sources(env, source, overwarn) + + if self.single_source and len(source) > 1 and target is None: + result = [] + if target is None: target = [None]*len(source) + for tgt, src in zip(target, source): + if not tgt is None: tgt = [tgt] + if not src is None: src = [src] + result.extend(self._execute(env, tgt, src, overwarn)) + return SCons.Node.NodeList(result) + + overwarn.warn() + + tlist, slist = self._create_nodes(env, target, source) + + # Check for errors with the specified target/source lists. + _node_errors(self, env, tlist, slist) + + # The targets are fine, so find or make the appropriate Executor to + # build this particular list of targets from this particular list of + # sources. + + executor = None + key = None + + if self.multi: + try: + executor = tlist[0].get_executor(create = 0) + except (AttributeError, IndexError): + pass + else: + executor.add_sources(slist) + + if executor is None: + if not self.action: + fmt = "Builder %s must have an action to build %s." + raise UserError(fmt % (self.get_name(env or self.env), + list(map(str,tlist)))) + key = self.action.batch_key(env or self.env, tlist, slist) + if key: + try: + executor = SCons.Executor.GetBatchExecutor(key) + except KeyError: + pass + else: + executor.add_batch(tlist, slist) + + if executor is None: + executor = SCons.Executor.Executor(self.action, env, [], + tlist, slist, executor_kw) + if key: + SCons.Executor.AddBatchExecutor(key, executor) + + # Now set up the relevant information in the target Nodes themselves. + for t in tlist: + t.cwd = env.fs.getcwd() + t.builder_set(self) + t.env_set(env) + t.add_source(slist) + t.set_executor(executor) + t.set_explicit(self.is_explicit) + + return SCons.Node.NodeList(tlist) + + def __call__(self, env, target=None, source=None, chdir=_null, **kw): + # We now assume that target and source are lists or None. + # The caller (typically Environment.BuilderWrapper) is + # responsible for converting any scalar values to lists. + if chdir is _null: + ekw = self.executor_kw + else: + ekw = self.executor_kw.copy() + ekw['chdir'] = chdir + if 'chdir' in ekw and SCons.Util.is_String(ekw['chdir']): + ekw['chdir'] = env.subst(ekw['chdir']) + if kw: + if 'srcdir' in kw: + def prependDirIfRelative(f, srcdir=kw['srcdir']): + import os.path + if SCons.Util.is_String(f) and not os.path.isabs(f): + f = os.path.join(srcdir, f) + return f + if not SCons.Util.is_List(source): + source = [source] + source = list(map(prependDirIfRelative, source)) + del kw['srcdir'] + if self.overrides: + env_kw = self.overrides.copy() + env_kw.update(kw) + else: + env_kw = kw + else: + env_kw = self.overrides + env = env.Override(env_kw) + return self._execute(env, target, source, OverrideWarner(kw), ekw) + + def adjust_suffix(self, suff): + if suff and not suff[0] in [ '.', '_', '$' ]: + return '.' + suff + return suff + + def get_prefix(self, env, sources=[]): + prefix = self.prefix + if callable(prefix): + prefix = prefix(env, sources) + return env.subst(prefix) + + def set_suffix(self, suffix): + if not callable(suffix): + suffix = self.adjust_suffix(suffix) + self.suffix = suffix + + def get_suffix(self, env, sources=[]): + suffix = self.suffix + if callable(suffix): + suffix = suffix(env, sources) + return env.subst(suffix) + + def set_src_suffix(self, src_suffix): + if not src_suffix: + src_suffix = [] + elif not SCons.Util.is_List(src_suffix): + src_suffix = [ src_suffix ] + self.src_suffix = [callable(suf) and suf or self.adjust_suffix(suf) for suf in src_suffix] + + def get_src_suffix(self, env): + """Get the first src_suffix in the list of src_suffixes.""" + ret = self.src_suffixes(env) + if not ret: + return '' + return ret[0] + + def add_emitter(self, suffix, emitter): + """Add a suffix-emitter mapping to this Builder. + + This assumes that emitter has been initialized with an + appropriate dictionary type, and will throw a TypeError if + not, so the caller is responsible for knowing that this is an + appropriate method to call for the Builder in question. + """ + self.emitter[suffix] = emitter + + def add_src_builder(self, builder): + """ + Add a new Builder to the list of src_builders. + + This requires wiping out cached values so that the computed + lists of source suffixes get re-calculated. + """ + self._memo = {} + self.src_builder.append(builder) + + def _get_sdict(self, env): + """ + Returns a dictionary mapping all of the source suffixes of all + src_builders of this Builder to the underlying Builder that + should be called first. + + This dictionary is used for each target specified, so we save a + lot of extra computation by memoizing it for each construction + environment. + + Note that this is re-computed each time, not cached, because there + might be changes to one of our source Builders (or one of their + source Builders, and so on, and so on...) that we can't "see." + + The underlying methods we call cache their computed values, + though, so we hope repeatedly aggregating them into a dictionary + like this won't be too big a hit. We may need to look for a + better way to do this if performance data show this has turned + into a significant bottleneck. + """ + sdict = {} + for bld in self.get_src_builders(env): + for suf in bld.src_suffixes(env): + sdict[suf] = bld + return sdict + + def src_builder_sources(self, env, source, overwarn={}): + sdict = self._get_sdict(env) + + src_suffixes = self.src_suffixes(env) + + lengths = list(set(map(len, src_suffixes))) + + def match_src_suffix(name, src_suffixes=src_suffixes, lengths=lengths): + node_suffixes = [name[-l:] for l in lengths] + for suf in src_suffixes: + if suf in node_suffixes: + return suf + return None + + result = [] + for s in SCons.Util.flatten(source): + if SCons.Util.is_String(s): + match_suffix = match_src_suffix(env.subst(s)) + if not match_suffix and not '.' in s: + src_suf = self.get_src_suffix(env) + s = self._adjustixes(s, None, src_suf)[0] + else: + match_suffix = match_src_suffix(s.name) + if match_suffix: + try: + bld = sdict[match_suffix] + except KeyError: + result.append(s) + else: + tlist = bld._execute(env, None, [s], overwarn) + # If the subsidiary Builder returned more than one + # target, then filter out any sources that this + # Builder isn't capable of building. + if len(tlist) > 1: + tlist = [t for t in tlist if match_src_suffix(t.name)] + result.extend(tlist) + else: + result.append(s) + + source_factory = env.get_factory(self.source_factory) + + return env.arg2nodes(result, source_factory) + + def _get_src_builders_key(self, env): + return id(env) + + @SCons.Memoize.CountDictCall(_get_src_builders_key) + def get_src_builders(self, env): + """ + Returns the list of source Builders for this Builder. + + This exists mainly to look up Builders referenced as + strings in the 'BUILDER' variable of the construction + environment and cache the result. + """ + memo_key = id(env) + try: + memo_dict = self._memo['get_src_builders'] + except KeyError: + memo_dict = {} + self._memo['get_src_builders'] = memo_dict + else: + try: + return memo_dict[memo_key] + except KeyError: + pass + + builders = [] + for bld in self.src_builder: + if SCons.Util.is_String(bld): + try: + bld = env['BUILDERS'][bld] + except KeyError: + continue + builders.append(bld) + + memo_dict[memo_key] = builders + return builders + + def _subst_src_suffixes_key(self, env): + return id(env) + + @SCons.Memoize.CountDictCall(_subst_src_suffixes_key) + def subst_src_suffixes(self, env): + """ + The suffix list may contain construction variable expansions, + so we have to evaluate the individual strings. To avoid doing + this over and over, we memoize the results for each construction + environment. + """ + memo_key = id(env) + try: + memo_dict = self._memo['subst_src_suffixes'] + except KeyError: + memo_dict = {} + self._memo['subst_src_suffixes'] = memo_dict + else: + try: + return memo_dict[memo_key] + except KeyError: + pass + suffixes = [env.subst(x) for x in self.src_suffix] + memo_dict[memo_key] = suffixes + return suffixes + + def src_suffixes(self, env): + """ + Returns the list of source suffixes for all src_builders of this + Builder. + + This is essentially a recursive descent of the src_builder "tree." + (This value isn't cached because there may be changes in a + src_builder many levels deep that we can't see.) + """ + sdict = {} + suffixes = self.subst_src_suffixes(env) + for s in suffixes: + sdict[s] = 1 + for builder in self.get_src_builders(env): + for s in builder.src_suffixes(env): + if s not in sdict: + sdict[s] = 1 + suffixes.append(s) + return suffixes + +class CompositeBuilder(SCons.Util.Proxy): + """A Builder Proxy whose main purpose is to always have + a DictCmdGenerator as its action, and to provide access + to the DictCmdGenerator's add_action() method. + """ + + def __init__(self, builder, cmdgen): + if SCons.Debug.track_instances: logInstanceCreation(self, 'Builder.CompositeBuilder') + SCons.Util.Proxy.__init__(self, builder) + + # cmdgen should always be an instance of DictCmdGenerator. + self.cmdgen = cmdgen + self.builder = builder + + __call__ = SCons.Util.Delegate('__call__') + + def add_action(self, suffix, action): + self.cmdgen.add_action(suffix, action) + self.set_src_suffix(self.cmdgen.src_suffixes()) + +def is_a_Builder(obj): + """"Returns True if the specified obj is one of our Builder classes. + + The test is complicated a bit by the fact that CompositeBuilder + is a proxy, not a subclass of BuilderBase. + """ + return (isinstance(obj, BuilderBase) + or isinstance(obj, CompositeBuilder) + or callable(obj)) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/CacheDir.py b/tools/scons/scons-local-3.0.5/SCons/CacheDir.py new file mode 100755 index 0000000000..81c74f0f65 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/CacheDir.py @@ -0,0 +1,282 @@ +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/CacheDir.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +__doc__ = """ +CacheDir support +""" + +import hashlib +import json +import os +import stat +import sys + +import SCons.Action +import SCons.Warnings + +cache_enabled = True +cache_debug = False +cache_force = False +cache_show = False +cache_readonly = False + +def CacheRetrieveFunc(target, source, env): + t = target[0] + fs = t.fs + cd = env.get_CacheDir() + cachedir, cachefile = cd.cachepath(t) + if not fs.exists(cachefile): + cd.CacheDebug('CacheRetrieve(%s): %s not in cache\n', t, cachefile) + return 1 + cd.CacheDebug('CacheRetrieve(%s): retrieving from %s\n', t, cachefile) + if SCons.Action.execute_actions: + if fs.islink(cachefile): + fs.symlink(fs.readlink(cachefile), t.get_internal_path()) + else: + env.copy_from_cache(cachefile, t.get_internal_path()) + try: + os.utime(cachefile, None) + except OSError: + pass + st = fs.stat(cachefile) + fs.chmod(t.get_internal_path(), stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE) + return 0 + +def CacheRetrieveString(target, source, env): + t = target[0] + fs = t.fs + cd = env.get_CacheDir() + cachedir, cachefile = cd.cachepath(t) + if t.fs.exists(cachefile): + return "Retrieved `%s' from cache" % t.get_internal_path() + return None + +CacheRetrieve = SCons.Action.Action(CacheRetrieveFunc, CacheRetrieveString) + +CacheRetrieveSilent = SCons.Action.Action(CacheRetrieveFunc, None) + +def CachePushFunc(target, source, env): + if cache_readonly: + return + + t = target[0] + if t.nocache: + return + fs = t.fs + cd = env.get_CacheDir() + cachedir, cachefile = cd.cachepath(t) + if fs.exists(cachefile): + # Don't bother copying it if it's already there. Note that + # usually this "shouldn't happen" because if the file already + # existed in cache, we'd have retrieved the file from there, + # not built it. This can happen, though, in a race, if some + # other person running the same build pushes their copy to + # the cache after we decide we need to build it but before our + # build completes. + cd.CacheDebug('CachePush(%s): %s already exists in cache\n', t, cachefile) + return + + cd.CacheDebug('CachePush(%s): pushing to %s\n', t, cachefile) + + tempfile = cachefile+'.tmp'+str(os.getpid()) + errfmt = "Unable to copy %s to cache. Cache file is %s" + + if not fs.isdir(cachedir): + try: + fs.makedirs(cachedir) + except EnvironmentError: + # We may have received an exception because another process + # has beaten us creating the directory. + if not fs.isdir(cachedir): + msg = errfmt % (str(target), cachefile) + raise SCons.Errors.EnvironmentError(msg) + + try: + if fs.islink(t.get_internal_path()): + fs.symlink(fs.readlink(t.get_internal_path()), tempfile) + else: + fs.copy2(t.get_internal_path(), tempfile) + fs.rename(tempfile, cachefile) + st = fs.stat(t.get_internal_path()) + fs.chmod(cachefile, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE) + except EnvironmentError: + # It's possible someone else tried writing the file at the + # same time we did, or else that there was some problem like + # the CacheDir being on a separate file system that's full. + # In any case, inability to push a file to cache doesn't affect + # the correctness of the build, so just print a warning. + msg = errfmt % (str(target), cachefile) + SCons.Warnings.warn(SCons.Warnings.CacheWriteErrorWarning, msg) + +CachePush = SCons.Action.Action(CachePushFunc, None) + +# Nasty hack to cut down to one warning for each cachedir path that needs +# upgrading. +warned = dict() + +class CacheDir(object): + + def __init__(self, path): + self.path = path + self.current_cache_debug = None + self.debugFP = None + self.config = dict() + if path is None: + return + # See if there's a config file in the cache directory. If there is, + # use it. If there isn't, and the directory exists and isn't empty, + # produce a warning. If the directory doesn't exist or is empty, + # write a config file. + config_file = os.path.join(path, 'config') + if not os.path.exists(config_file): + # A note: There is a race hazard here, if two processes start and + # attempt to create the cache directory at the same time. However, + # python doesn't really give you the option to do exclusive file + # creation (it doesn't even give you the option to error on opening + # an existing file for writing...). The ordering of events here + # as an attempt to alleviate this, on the basis that it's a pretty + # unlikely occurence (it'd require two builds with a brand new cache + # directory) + if os.path.isdir(path) and len(os.listdir(path)) != 0: + self.config['prefix_len'] = 1 + # When building the project I was testing this on, the warning + # was output over 20 times. That seems excessive + global warned + if self.path not in warned: + msg = "Please upgrade your cache by running " +\ + " scons-configure-cache.py " + self.path + SCons.Warnings.warn(SCons.Warnings.CacheVersionWarning, msg) + warned[self.path] = True + else: + if not os.path.isdir(path): + try: + os.makedirs(path) + except OSError: + # If someone else is trying to create the directory at + # the same time as me, bad things will happen + msg = "Failed to create cache directory " + path + raise SCons.Errors.EnvironmentError(msg) + + self.config['prefix_len'] = 2 + if not os.path.exists(config_file): + try: + with open(config_file, 'w') as config: + json.dump(self.config, config) + except: + msg = "Failed to write cache configuration for " + path + raise SCons.Errors.EnvironmentError(msg) + else: + try: + with open(config_file) as config: + self.config = json.load(config) + except ValueError: + msg = "Failed to read cache configuration for " + path + raise SCons.Errors.EnvironmentError(msg) + + + def CacheDebug(self, fmt, target, cachefile): + if cache_debug != self.current_cache_debug: + if cache_debug == '-': + self.debugFP = sys.stdout + elif cache_debug: + self.debugFP = open(cache_debug, 'w') + else: + self.debugFP = None + self.current_cache_debug = cache_debug + if self.debugFP: + self.debugFP.write(fmt % (target, os.path.split(cachefile)[1])) + + def is_enabled(self): + return cache_enabled and not self.path is None + + def is_readonly(self): + return cache_readonly + + def cachepath(self, node): + """ + """ + if not self.is_enabled(): + return None, None + + sig = node.get_cachedir_bsig() + + subdir = sig[:self.config['prefix_len']].upper() + + dir = os.path.join(self.path, subdir) + return dir, os.path.join(dir, sig) + + def retrieve(self, node): + """ + This method is called from multiple threads in a parallel build, + so only do thread safe stuff here. Do thread unsafe stuff in + built(). + + Note that there's a special trick here with the execute flag + (one that's not normally done for other actions). Basically + if the user requested a no_exec (-n) build, then + SCons.Action.execute_actions is set to 0 and when any action + is called, it does its showing but then just returns zero + instead of actually calling the action execution operation. + The problem for caching is that if the file does NOT exist in + cache then the CacheRetrieveString won't return anything to + show for the task, but the Action.__call__ won't call + CacheRetrieveFunc; instead it just returns zero, which makes + the code below think that the file *was* successfully + retrieved from the cache, therefore it doesn't do any + subsequent building. However, the CacheRetrieveString didn't + print anything because it didn't actually exist in the cache, + and no more build actions will be performed, so the user just + sees nothing. The fix is to tell Action.__call__ to always + execute the CacheRetrieveFunc and then have the latter + explicitly check SCons.Action.execute_actions itself. + """ + if not self.is_enabled(): + return False + + env = node.get_build_env() + if cache_show: + if CacheRetrieveSilent(node, [], env, execute=1) == 0: + node.build(presub=0, execute=0) + return True + else: + if CacheRetrieve(node, [], env, execute=1) == 0: + return True + + return False + + def push(self, node): + if self.is_readonly() or not self.is_enabled(): + return + return CachePush(node, [], node.get_build_env()) + + def push_if_forced(self, node): + if cache_force: + return self.push(node) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Conftest.py b/tools/scons/scons-local-3.0.5/SCons/Conftest.py new file mode 100755 index 0000000000..84aa9925e4 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Conftest.py @@ -0,0 +1,812 @@ +"""SCons.Conftest + +Autoconf-like configuration support; low level implementation of tests. +""" + +# +# Copyright (c) 2003 Stichting NLnet Labs +# Copyright (c) 2001, 2002, 2003 Steven Knight +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +# +# The purpose of this module is to define how a check is to be performed. +# Use one of the Check...() functions below. +# + +# +# A context class is used that defines functions for carrying out the tests, +# logging and messages. The following methods and members must be present: +# +# context.Display(msg) Function called to print messages that are normally +# displayed for the user. Newlines are explicitly used. +# The text should also be written to the logfile! +# +# context.Log(msg) Function called to write to a log file. +# +# context.BuildProg(text, ext) +# Function called to build a program, using "ext" for the +# file extention. Must return an empty string for +# success, an error message for failure. +# For reliable test results building should be done just +# like an actual program would be build, using the same +# command and arguments (including configure results so +# far). +# +# context.CompileProg(text, ext) +# Function called to compile a program, using "ext" for +# the file extention. Must return an empty string for +# success, an error message for failure. +# For reliable test results compiling should be done just +# like an actual source file would be compiled, using the +# same command and arguments (including configure results +# so far). +# +# context.AppendLIBS(lib_name_list) +# Append "lib_name_list" to the value of LIBS. +# "lib_namelist" is a list of strings. +# Return the value of LIBS before changing it (any type +# can be used, it is passed to SetLIBS() later.) +# +# context.PrependLIBS(lib_name_list) +# Prepend "lib_name_list" to the value of LIBS. +# "lib_namelist" is a list of strings. +# Return the value of LIBS before changing it (any type +# can be used, it is passed to SetLIBS() later.) +# +# context.SetLIBS(value) +# Set LIBS to "value". The type of "value" is what +# AppendLIBS() returned. +# Return the value of LIBS before changing it (any type +# can be used, it is passed to SetLIBS() later.) +# +# context.headerfilename +# Name of file to append configure results to, usually +# "confdefs.h". +# The file must not exist or be empty when starting. +# Empty or None to skip this (some tests will not work!). +# +# context.config_h (may be missing). If present, must be a string, which +# will be filled with the contents of a config_h file. +# +# context.vardict Dictionary holding variables used for the tests and +# stores results from the tests, used for the build +# commands. +# Normally contains "CC", "LIBS", "CPPFLAGS", etc. +# +# context.havedict Dictionary holding results from the tests that are to +# be used inside a program. +# Names often start with "HAVE_". These are zero +# (feature not present) or one (feature present). Other +# variables may have any value, e.g., "PERLVERSION" can +# be a number and "SYSTEMNAME" a string. +# + +import re + +# +# PUBLIC VARIABLES +# + +LogInputFiles = 1 # Set that to log the input files in case of a failed test +LogErrorMessages = 1 # Set that to log Conftest-generated error messages + +# +# PUBLIC FUNCTIONS +# + +# Generic remarks: +# - When a language is specified which is not supported the test fails. The +# message is a bit different, because not all the arguments for the normal +# message are available yet (chicken-egg problem). + + +def CheckBuilder(context, text = None, language = None): + """ + Configure check to see if the compiler works. + Note that this uses the current value of compiler and linker flags, make + sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly. + "language" should be "C" or "C++" and is used to select the compiler. + Default is "C". + "text" may be used to specify the code to be build. + Returns an empty string for success, an error message for failure. + """ + lang, suffix, msg = _lang2suffix(language) + if msg: + context.Display("%s\n" % msg) + return msg + + if not text: + text = """ +int main(void) { + return 0; +} +""" + + context.Display("Checking if building a %s file works... " % lang) + ret = context.BuildProg(text, suffix) + _YesNoResult(context, ret, None, text) + return ret + +def CheckCC(context): + """ + Configure check for a working C compiler. + + This checks whether the C compiler, as defined in the $CC construction + variable, can compile a C source file. It uses the current $CCCOM value + too, so that it can test against non working flags. + + """ + context.Display("Checking whether the C compiler works... ") + text = """ +int main(void) +{ + return 0; +} +""" + ret = _check_empty_program(context, 'CC', text, 'C') + _YesNoResult(context, ret, None, text) + return ret + +def CheckSHCC(context): + """ + Configure check for a working shared C compiler. + + This checks whether the C compiler, as defined in the $SHCC construction + variable, can compile a C source file. It uses the current $SHCCCOM value + too, so that it can test against non working flags. + + """ + context.Display("Checking whether the (shared) C compiler works... ") + text = """ +int foo(void) +{ + return 0; +} +""" + ret = _check_empty_program(context, 'SHCC', text, 'C', use_shared = True) + _YesNoResult(context, ret, None, text) + return ret + +def CheckCXX(context): + """ + Configure check for a working CXX compiler. + + This checks whether the CXX compiler, as defined in the $CXX construction + variable, can compile a CXX source file. It uses the current $CXXCOM value + too, so that it can test against non working flags. + + """ + context.Display("Checking whether the C++ compiler works... ") + text = """ +int main(void) +{ + return 0; +} +""" + ret = _check_empty_program(context, 'CXX', text, 'C++') + _YesNoResult(context, ret, None, text) + return ret + +def CheckSHCXX(context): + """ + Configure check for a working shared CXX compiler. + + This checks whether the CXX compiler, as defined in the $SHCXX construction + variable, can compile a CXX source file. It uses the current $SHCXXCOM value + too, so that it can test against non working flags. + + """ + context.Display("Checking whether the (shared) C++ compiler works... ") + text = """ +int main(void) +{ + return 0; +} +""" + ret = _check_empty_program(context, 'SHCXX', text, 'C++', use_shared = True) + _YesNoResult(context, ret, None, text) + return ret + +def _check_empty_program(context, comp, text, language, use_shared = False): + """Return 0 on success, 1 otherwise.""" + if comp not in context.env or not context.env[comp]: + # The compiler construction variable is not set or empty + return 1 + + lang, suffix, msg = _lang2suffix(language) + if msg: + return 1 + + if use_shared: + return context.CompileSharedObject(text, suffix) + else: + return context.CompileProg(text, suffix) + + +def CheckFunc(context, function_name, header = None, language = None): + """ + Configure check for a function "function_name". + "language" should be "C" or "C++" and is used to select the compiler. + Default is "C". + Optional "header" can be defined to define a function prototype, include a + header file or anything else that comes before main(). + Sets HAVE_function_name in context.havedict according to the result. + Note that this uses the current value of compiler and linker flags, make + sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly. + Returns an empty string for success, an error message for failure. + """ + + # Remarks from autoconf: + # - Don't include because on OSF/1 3.0 it includes + # which includes which contains a prototype for select. + # Similarly for bzero. + # - assert.h is included to define __stub macros and hopefully few + # prototypes, which can conflict with char $1(); below. + # - Override any gcc2 internal prototype to avoid an error. + # - We use char for the function declaration because int might match the + # return type of a gcc2 builtin and then its argument prototype would + # still apply. + # - The GNU C library defines this for functions which it implements to + # always fail with ENOSYS. Some functions are actually named something + # starting with __ and the normal name is an alias. + + if context.headerfilename: + includetext = '#include "%s"' % context.headerfilename + else: + includetext = '' + if not header: + header = """ +#ifdef __cplusplus +extern "C" +#endif +char %s();""" % function_name + + lang, suffix, msg = _lang2suffix(language) + if msg: + context.Display("Cannot check for %s(): %s\n" % (function_name, msg)) + return msg + + text = """ +%(include)s +#include +%(hdr)s + +int main(void) { +#if defined (__stub_%(name)s) || defined (__stub___%(name)s) + fail fail fail +#else + %(name)s(); +#endif + + return 0; +} +""" % { 'name': function_name, + 'include': includetext, + 'hdr': header } + + context.Display("Checking for %s function %s()... " % (lang, function_name)) + ret = context.BuildProg(text, suffix) + _YesNoResult(context, ret, "HAVE_" + function_name, text, + "Define to 1 if the system has the function `%s'." %\ + function_name) + return ret + + +def CheckHeader(context, header_name, header = None, language = None, + include_quotes = None): + """ + Configure check for a C or C++ header file "header_name". + Optional "header" can be defined to do something before including the + header file (unusual, supported for consistency). + "language" should be "C" or "C++" and is used to select the compiler. + Default is "C". + Sets HAVE_header_name in context.havedict according to the result. + Note that this uses the current value of compiler and linker flags, make + sure $CFLAGS and $CPPFLAGS are set correctly. + Returns an empty string for success, an error message for failure. + """ + # Why compile the program instead of just running the preprocessor? + # It is possible that the header file exists, but actually using it may + # fail (e.g., because it depends on other header files). Thus this test is + # more strict. It may require using the "header" argument. + # + # Use <> by default, because the check is normally used for system header + # files. SCons passes '""' to overrule this. + + # Include "confdefs.h" first, so that the header can use HAVE_HEADER_H. + if context.headerfilename: + includetext = '#include "%s"\n' % context.headerfilename + else: + includetext = '' + if not header: + header = "" + + lang, suffix, msg = _lang2suffix(language) + if msg: + context.Display("Cannot check for header file %s: %s\n" + % (header_name, msg)) + return msg + + if not include_quotes: + include_quotes = "<>" + + text = "%s%s\n#include %s%s%s\n\n" % (includetext, header, + include_quotes[0], header_name, include_quotes[1]) + + context.Display("Checking for %s header file %s... " % (lang, header_name)) + ret = context.CompileProg(text, suffix) + _YesNoResult(context, ret, "HAVE_" + header_name, text, + "Define to 1 if you have the <%s> header file." % header_name) + return ret + + +def CheckType(context, type_name, fallback = None, + header = None, language = None): + """ + Configure check for a C or C++ type "type_name". + Optional "header" can be defined to include a header file. + "language" should be "C" or "C++" and is used to select the compiler. + Default is "C". + Sets HAVE_type_name in context.havedict according to the result. + Note that this uses the current value of compiler and linker flags, make + sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly. + Returns an empty string for success, an error message for failure. + """ + + # Include "confdefs.h" first, so that the header can use HAVE_HEADER_H. + if context.headerfilename: + includetext = '#include "%s"' % context.headerfilename + else: + includetext = '' + if not header: + header = "" + + lang, suffix, msg = _lang2suffix(language) + if msg: + context.Display("Cannot check for %s type: %s\n" % (type_name, msg)) + return msg + + # Remarks from autoconf about this test: + # - Grepping for the type in include files is not reliable (grep isn't + # portable anyway). + # - Using "TYPE my_var;" doesn't work for const qualified types in C++. + # Adding an initializer is not valid for some C++ classes. + # - Using the type as parameter to a function either fails for K&$ C or for + # C++. + # - Using "TYPE *my_var;" is valid in C for some types that are not + # declared (struct something). + # - Using "sizeof(TYPE)" is valid when TYPE is actually a variable. + # - Using the previous two together works reliably. + text = """ +%(include)s +%(header)s + +int main(void) { + if ((%(name)s *) 0) + return 0; + if (sizeof (%(name)s)) + return 0; +} +""" % { 'include': includetext, + 'header': header, + 'name': type_name } + + context.Display("Checking for %s type %s... " % (lang, type_name)) + ret = context.BuildProg(text, suffix) + _YesNoResult(context, ret, "HAVE_" + type_name, text, + "Define to 1 if the system has the type `%s'." % type_name) + if ret and fallback and context.headerfilename: + f = open(context.headerfilename, "a") + f.write("typedef %s %s;\n" % (fallback, type_name)) + f.close() + + return ret + +def CheckTypeSize(context, type_name, header = None, language = None, expect = None): + """This check can be used to get the size of a given type, or to check whether + the type is of expected size. + + Arguments: + - type : str + the type to check + - includes : sequence + list of headers to include in the test code before testing the type + - language : str + 'C' or 'C++' + - expect : int + if given, will test wether the type has the given number of bytes. + If not given, will automatically find the size. + + Returns: + status : int + 0 if the check failed, or the found size of the type if the check succeeded.""" + + # Include "confdefs.h" first, so that the header can use HAVE_HEADER_H. + if context.headerfilename: + includetext = '#include "%s"' % context.headerfilename + else: + includetext = '' + + if not header: + header = "" + + lang, suffix, msg = _lang2suffix(language) + if msg: + context.Display("Cannot check for %s type: %s\n" % (type_name, msg)) + return msg + + src = includetext + header + if not expect is None: + # Only check if the given size is the right one + context.Display('Checking %s is %d bytes... ' % (type_name, expect)) + + # test code taken from autoconf: this is a pretty clever hack to find that + # a type is of a given size using only compilation. This speeds things up + # quite a bit compared to straightforward code using TryRun + src = src + r""" +typedef %s scons_check_type; + +int main(void) +{ + static int test_array[1 - 2 * !(((long int) (sizeof(scons_check_type))) == %d)]; + test_array[0] = 0; + + return 0; +} +""" + + st = context.CompileProg(src % (type_name, expect), suffix) + if not st: + context.Display("yes\n") + _Have(context, "SIZEOF_%s" % type_name, expect, + "The size of `%s', as computed by sizeof." % type_name) + return expect + else: + context.Display("no\n") + _LogFailed(context, src, st) + return 0 + else: + # Only check if the given size is the right one + context.Message('Checking size of %s ... ' % type_name) + + # We have to be careful with the program we wish to test here since + # compilation will be attempted using the current environment's flags. + # So make sure that the program will compile without any warning. For + # example using: 'int main(int argc, char** argv)' will fail with the + # '-Wall -Werror' flags since the variables argc and argv would not be + # used in the program... + # + src = src + """ +#include +#include +int main(void) { + printf("%d", (int)sizeof(""" + type_name + """)); + return 0; +} + """ + st, out = context.RunProg(src, suffix) + try: + size = int(out) + except ValueError: + # If cannot convert output of test prog to an integer (the size), + # something went wront, so just fail + st = 1 + size = 0 + + if not st: + context.Display("yes\n") + _Have(context, "SIZEOF_%s" % type_name, size, + "The size of `%s', as computed by sizeof." % type_name) + return size + else: + context.Display("no\n") + _LogFailed(context, src, st) + return 0 + + return 0 + +def CheckDeclaration(context, symbol, includes = None, language = None): + """Checks whether symbol is declared. + + Use the same test as autoconf, that is test whether the symbol is defined + as a macro or can be used as an r-value. + + Arguments: + symbol : str + the symbol to check + includes : str + Optional "header" can be defined to include a header file. + language : str + only C and C++ supported. + + Returns: + status : bool + True if the check failed, False if succeeded.""" + + # Include "confdefs.h" first, so that the header can use HAVE_HEADER_H. + if context.headerfilename: + includetext = '#include "%s"' % context.headerfilename + else: + includetext = '' + + if not includes: + includes = "" + + lang, suffix, msg = _lang2suffix(language) + if msg: + context.Display("Cannot check for declaration %s: %s\n" % (symbol, msg)) + return msg + + src = includetext + includes + context.Display('Checking whether %s is declared... ' % symbol) + + src = src + r""" +int main(void) +{ +#ifndef %s + (void) %s; +#endif + ; + return 0; +} +""" % (symbol, symbol) + + st = context.CompileProg(src, suffix) + _YesNoResult(context, st, "HAVE_DECL_" + symbol, src, + "Set to 1 if %s is defined." % symbol) + return st + +def CheckLib(context, libs, func_name = None, header = None, + extra_libs = None, call = None, language = None, autoadd = 1, + append = True): + """ + Configure check for a C or C++ libraries "libs". Searches through + the list of libraries, until one is found where the test succeeds. + Tests if "func_name" or "call" exists in the library. Note: if it exists + in another library the test succeeds anyway! + Optional "header" can be defined to include a header file. If not given a + default prototype for "func_name" is added. + Optional "extra_libs" is a list of library names to be added after + "lib_name" in the build command. To be used for libraries that "lib_name" + depends on. + Optional "call" replaces the call to "func_name" in the test code. It must + consist of complete C statements, including a trailing ";". + Both "func_name" and "call" arguments are optional, and in that case, just + linking against the libs is tested. + "language" should be "C" or "C++" and is used to select the compiler. + Default is "C". + Note that this uses the current value of compiler and linker flags, make + sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly. + Returns an empty string for success, an error message for failure. + """ + # Include "confdefs.h" first, so that the header can use HAVE_HEADER_H. + if context.headerfilename: + includetext = '#include "%s"' % context.headerfilename + else: + includetext = '' + if not header: + header = "" + + text = """ +%s +%s""" % (includetext, header) + + # Add a function declaration if needed. + if func_name and func_name != "main": + if not header: + text = text + """ +#ifdef __cplusplus +extern "C" +#endif +char %s(); +""" % func_name + + # The actual test code. + if not call: + call = "%s();" % func_name + + # if no function to test, leave main() blank + text = text + """ +int +main() { + %s +return 0; +} +""" % (call or "") + + if call: + i = call.find("\n") + if i > 0: + calltext = call[:i] + ".." + elif call[-1] == ';': + calltext = call[:-1] + else: + calltext = call + + for lib_name in libs: + + lang, suffix, msg = _lang2suffix(language) + if msg: + context.Display("Cannot check for library %s: %s\n" % (lib_name, msg)) + return msg + + # if a function was specified to run in main(), say it + if call: + context.Display("Checking for %s in %s library %s... " + % (calltext, lang, lib_name)) + # otherwise, just say the name of library and language + else: + context.Display("Checking for %s library %s... " + % (lang, lib_name)) + + if lib_name: + l = [ lib_name ] + if extra_libs: + l.extend(extra_libs) + if append: + oldLIBS = context.AppendLIBS(l) + else: + oldLIBS = context.PrependLIBS(l) + sym = "HAVE_LIB" + lib_name + else: + oldLIBS = -1 + sym = None + + ret = context.BuildProg(text, suffix) + + _YesNoResult(context, ret, sym, text, + "Define to 1 if you have the `%s' library." % lib_name) + if oldLIBS != -1 and (ret or not autoadd): + context.SetLIBS(oldLIBS) + + if not ret: + return ret + + return ret + +def CheckProg(context, prog_name): + """ + Configure check for a specific program. + + Check whether program prog_name exists in path. If it is found, + returns the path for it, otherwise returns None. + """ + context.Display("Checking whether %s program exists..." % prog_name) + path = context.env.WhereIs(prog_name) + if path: + context.Display(path + "\n") + else: + context.Display("no\n") + return path + + +# +# END OF PUBLIC FUNCTIONS +# + +def _YesNoResult(context, ret, key, text, comment = None): + """ + Handle the result of a test with a "yes" or "no" result. + + :Parameters: + - `ret` is the return value: empty if OK, error message when not. + - `key` is the name of the symbol to be defined (HAVE_foo). + - `text` is the source code of the program used for testing. + - `comment` is the C comment to add above the line defining the symbol (the comment is automatically put inside a /\* \*/). If None, no comment is added. + """ + if key: + _Have(context, key, not ret, comment) + if ret: + context.Display("no\n") + _LogFailed(context, text, ret) + else: + context.Display("yes\n") + + +def _Have(context, key, have, comment = None): + """ + Store result of a test in context.havedict and context.headerfilename. + + :Parameters: + - `key` - is a "HAVE_abc" name. It is turned into all CAPITALS and non-alphanumerics are replaced by an underscore. + - `have` - value as it should appear in the header file, include quotes when desired and escape special characters! + - `comment` is the C comment to add above the line defining the symbol (the comment is automatically put inside a /\* \*/). If None, no comment is added. + + + The value of "have" can be: + - 1 - Feature is defined, add "#define key". + - 0 - Feature is not defined, add "/\* #undef key \*/". Adding "undef" is what autoconf does. Not useful for the compiler, but it shows that the test was done. + - number - Feature is defined to this number "#define key have". Doesn't work for 0 or 1, use a string then. + - string - Feature is defined to this string "#define key have". + + + """ + key_up = key.upper() + key_up = re.sub('[^A-Z0-9_]', '_', key_up) + context.havedict[key_up] = have + if have == 1: + line = "#define %s 1\n" % key_up + elif have == 0: + line = "/* #undef %s */\n" % key_up + elif isinstance(have, int): + line = "#define %s %d\n" % (key_up, have) + else: + line = "#define %s %s\n" % (key_up, str(have)) + + if comment is not None: + lines = "\n/* %s */\n" % comment + line + else: + lines = "\n" + line + + if context.headerfilename: + f = open(context.headerfilename, "a") + f.write(lines) + f.close() + elif hasattr(context,'config_h'): + context.config_h = context.config_h + lines + + +def _LogFailed(context, text, msg): + """ + Write to the log about a failed program. + Add line numbers, so that error messages can be understood. + """ + if LogInputFiles: + context.Log("Failed program was:\n") + lines = text.split('\n') + if len(lines) and lines[-1] == '': + lines = lines[:-1] # remove trailing empty line + n = 1 + for line in lines: + context.Log("%d: %s\n" % (n, line)) + n = n + 1 + if LogErrorMessages: + context.Log("Error message: %s\n" % msg) + + +def _lang2suffix(lang): + """ + Convert a language name to a suffix. + When "lang" is empty or None C is assumed. + Returns a tuple (lang, suffix, None) when it works. + For an unrecognized language returns (None, None, msg). + + Where: + - lang = the unified language name + - suffix = the suffix, including the leading dot + - msg = an error message + """ + if not lang or lang in ["C", "c"]: + return ("C", ".c", None) + if lang in ["c++", "C++", "cpp", "CXX", "cxx"]: + return ("C++", ".cpp", None) + + return None, None, "Unsupported language: %s" % lang + + +# vim: set sw=4 et sts=4 tw=79 fo+=l: + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Debug.py b/tools/scons/scons-local-3.0.5/SCons/Debug.py new file mode 100755 index 0000000000..be19a019e9 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Debug.py @@ -0,0 +1,243 @@ +"""SCons.Debug + +Code for debugging SCons internal things. Shouldn't be +needed by most users. Quick shortcuts: + +from SCons.Debug import caller_trace +caller_trace() + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Debug.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os +import sys +import time +import weakref +import inspect + +# Global variable that gets set to 'True' by the Main script, +# when the creation of class instances should get tracked. +track_instances = False +# List of currently tracked classes +tracked_classes = {} + +def logInstanceCreation(instance, name=None): + if name is None: + name = instance.__class__.__name__ + if name not in tracked_classes: + tracked_classes[name] = [] + if hasattr(instance, '__dict__'): + tracked_classes[name].append(weakref.ref(instance)) + else: + # weakref doesn't seem to work when the instance + # contains only slots... + tracked_classes[name].append(instance) + +def string_to_classes(s): + if s == '*': + return sorted(tracked_classes.keys()) + else: + return s.split() + +def fetchLoggedInstances(classes="*"): + classnames = string_to_classes(classes) + return [(cn, len(tracked_classes[cn])) for cn in classnames] + +def countLoggedInstances(classes, file=sys.stdout): + for classname in string_to_classes(classes): + file.write("%s: %d\n" % (classname, len(tracked_classes[classname]))) + +def listLoggedInstances(classes, file=sys.stdout): + for classname in string_to_classes(classes): + file.write('\n%s:\n' % classname) + for ref in tracked_classes[classname]: + if inspect.isclass(ref): + obj = ref() + else: + obj = ref + if obj is not None: + file.write(' %s\n' % repr(obj)) + +def dumpLoggedInstances(classes, file=sys.stdout): + for classname in string_to_classes(classes): + file.write('\n%s:\n' % classname) + for ref in tracked_classes[classname]: + obj = ref() + if obj is not None: + file.write(' %s:\n' % obj) + for key, value in obj.__dict__.items(): + file.write(' %20s : %s\n' % (key, value)) + + + +if sys.platform[:5] == "linux": + # Linux doesn't actually support memory usage stats from getrusage(). + def memory(): + with open('/proc/self/stat') as f: + mstr = f.read() + mstr = mstr.split()[22] + return int(mstr) +elif sys.platform[:6] == 'darwin': + #TODO really get memory stats for OS X + def memory(): + return 0 +else: + try: + import resource + except ImportError: + try: + import win32process + import win32api + except ImportError: + def memory(): + return 0 + else: + def memory(): + process_handle = win32api.GetCurrentProcess() + memory_info = win32process.GetProcessMemoryInfo( process_handle ) + return memory_info['PeakWorkingSetSize'] + else: + def memory(): + res = resource.getrusage(resource.RUSAGE_SELF) + return res[4] + +# returns caller's stack +def caller_stack(): + import traceback + tb = traceback.extract_stack() + # strip itself and the caller from the output + tb = tb[:-2] + result = [] + for back in tb: + # (filename, line number, function name, text) + key = back[:3] + result.append('%s:%d(%s)' % func_shorten(key)) + return result + +caller_bases = {} +caller_dicts = {} + +def caller_trace(back=0): + """ + Trace caller stack and save info into global dicts, which + are printed automatically at the end of SCons execution. + """ + global caller_bases, caller_dicts + import traceback + tb = traceback.extract_stack(limit=3+back) + tb.reverse() + callee = tb[1][:3] + caller_bases[callee] = caller_bases.get(callee, 0) + 1 + for caller in tb[2:]: + caller = callee + caller[:3] + try: + entry = caller_dicts[callee] + except KeyError: + caller_dicts[callee] = entry = {} + entry[caller] = entry.get(caller, 0) + 1 + callee = caller + +# print a single caller and its callers, if any +def _dump_one_caller(key, file, level=0): + leader = ' '*level + for v,c in sorted([(-v,c) for c,v in caller_dicts[key].items()]): + file.write("%s %6d %s:%d(%s)\n" % ((leader,-v) + func_shorten(c[-3:]))) + if c in caller_dicts: + _dump_one_caller(c, file, level+1) + +# print each call tree +def dump_caller_counts(file=sys.stdout): + for k in sorted(caller_bases.keys()): + file.write("Callers of %s:%d(%s), %d calls:\n" + % (func_shorten(k) + (caller_bases[k],))) + _dump_one_caller(k, file) + +shorten_list = [ + ( '/scons/SCons/', 1), + ( '/src/engine/SCons/', 1), + ( '/usr/lib/python', 0), +] + +if os.sep != '/': + shorten_list = [(t[0].replace('/', os.sep), t[1]) for t in shorten_list] + +def func_shorten(func_tuple): + f = func_tuple[0] + for t in shorten_list: + i = f.find(t[0]) + if i >= 0: + if t[1]: + i = i + len(t[0]) + return (f[i:],)+func_tuple[1:] + return func_tuple + + +TraceFP = {} +if sys.platform == 'win32': + TraceDefault = 'con' +else: + TraceDefault = '/dev/tty' + +TimeStampDefault = None +StartTime = time.time() +PreviousTime = StartTime + +def Trace(msg, file=None, mode='w', tstamp=None): + """Write a trace message to a file. Whenever a file is specified, + it becomes the default for the next call to Trace().""" + global TraceDefault + global TimeStampDefault + global PreviousTime + if file is None: + file = TraceDefault + else: + TraceDefault = file + if tstamp is None: + tstamp = TimeStampDefault + else: + TimeStampDefault = tstamp + try: + fp = TraceFP[file] + except KeyError: + try: + fp = TraceFP[file] = open(file, mode) + except TypeError: + # Assume we were passed an open file pointer. + fp = file + if tstamp: + now = time.time() + fp.write('%8.4f %8.4f: ' % (now - StartTime, now - PreviousTime)) + PreviousTime = now + fp.write(msg) + fp.flush() + fp.close() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Defaults.py b/tools/scons/scons-local-3.0.5/SCons/Defaults.py new file mode 100755 index 0000000000..15ad91e27f --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Defaults.py @@ -0,0 +1,595 @@ +"""SCons.Defaults + +Builders and other things for the local site. Here's where we'll +duplicate the functionality of autoconf until we move it into the +installation procedure or use something like qmconf. + +The code that reads the registry to find MSVC components was borrowed +from distutils.msvccompiler. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +from __future__ import division + +__revision__ = "src/engine/SCons/Defaults.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + + +import os +import errno +import shutil +import stat +import time +import sys + +import SCons.Action +import SCons.Builder +import SCons.CacheDir +import SCons.Environment +import SCons.PathList +import SCons.Subst +import SCons.Tool + +# A placeholder for a default Environment (for fetching source files +# from source code management systems and the like). This must be +# initialized later, after the top-level directory is set by the calling +# interface. +_default_env = None + +# Lazily instantiate the default environment so the overhead of creating +# it doesn't apply when it's not needed. +def _fetch_DefaultEnvironment(*args, **kw): + """ + Returns the already-created default construction environment. + """ + global _default_env + return _default_env + +def DefaultEnvironment(*args, **kw): + """ + Initial public entry point for creating the default construction + Environment. + + After creating the environment, we overwrite our name + (DefaultEnvironment) with the _fetch_DefaultEnvironment() function, + which more efficiently returns the initialized default construction + environment without checking for its existence. + + (This function still exists with its _default_check because someone + else (*cough* Script/__init__.py *cough*) may keep a reference + to this function. So we can't use the fully functional idiom of + having the name originally be a something that *only* creates the + construction environment and then overwrites the name.) + """ + global _default_env + if not _default_env: + import SCons.Util + _default_env = SCons.Environment.Environment(*args, **kw) + if SCons.Util.md5: + _default_env.Decider('MD5') + else: + _default_env.Decider('timestamp-match') + global DefaultEnvironment + DefaultEnvironment = _fetch_DefaultEnvironment + _default_env._CacheDir_path = None + return _default_env + +# Emitters for setting the shared attribute on object files, +# and an action for checking that all of the source files +# going into a shared library are, in fact, shared. +def StaticObjectEmitter(target, source, env): + for tgt in target: + tgt.attributes.shared = None + return (target, source) + +def SharedObjectEmitter(target, source, env): + for tgt in target: + tgt.attributes.shared = 1 + return (target, source) + +def SharedFlagChecker(source, target, env): + same = env.subst('$STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME') + if same == '0' or same == '' or same == 'False': + for src in source: + try: + shared = src.attributes.shared + except AttributeError: + shared = None + if not shared: + raise SCons.Errors.UserError("Source file: %s is static and is not compatible with shared target: %s" % (src, target[0])) + +SharedCheck = SCons.Action.Action(SharedFlagChecker, None) + +# Some people were using these variable name before we made +# SourceFileScanner part of the public interface. Don't break their +# SConscript files until we've given them some fair warning and a +# transition period. +CScan = SCons.Tool.CScanner +DScan = SCons.Tool.DScanner +LaTeXScan = SCons.Tool.LaTeXScanner +ObjSourceScan = SCons.Tool.SourceFileScanner +ProgScan = SCons.Tool.ProgramScanner + +# These aren't really tool scanners, so they don't quite belong with +# the rest of those in Tool/__init__.py, but I'm not sure where else +# they should go. Leave them here for now. +import SCons.Scanner.Dir +DirScanner = SCons.Scanner.Dir.DirScanner() +DirEntryScanner = SCons.Scanner.Dir.DirEntryScanner() + +# Actions for common languages. +CAction = SCons.Action.Action("$CCCOM", "$CCCOMSTR") +ShCAction = SCons.Action.Action("$SHCCCOM", "$SHCCCOMSTR") +CXXAction = SCons.Action.Action("$CXXCOM", "$CXXCOMSTR") +ShCXXAction = SCons.Action.Action("$SHCXXCOM", "$SHCXXCOMSTR") + +DAction = SCons.Action.Action("$DCOM", "$DCOMSTR") +ShDAction = SCons.Action.Action("$SHDCOM", "$SHDCOMSTR") + +ASAction = SCons.Action.Action("$ASCOM", "$ASCOMSTR") +ASPPAction = SCons.Action.Action("$ASPPCOM", "$ASPPCOMSTR") + +LinkAction = SCons.Action.Action("$LINKCOM", "$LINKCOMSTR") +ShLinkAction = SCons.Action.Action("$SHLINKCOM", "$SHLINKCOMSTR") + +LdModuleLinkAction = SCons.Action.Action("$LDMODULECOM", "$LDMODULECOMSTR") + +# Common tasks that we allow users to perform in platform-independent +# ways by creating ActionFactory instances. +ActionFactory = SCons.Action.ActionFactory + +def get_paths_str(dest): + # If dest is a list, we need to manually call str() on each element + if SCons.Util.is_List(dest): + elem_strs = [] + for element in dest: + elem_strs.append('"' + str(element) + '"') + return '[' + ', '.join(elem_strs) + ']' + else: + return '"' + str(dest) + '"' + +permission_dic = { + 'u':{ + 'r':stat.S_IRUSR, + 'w':stat.S_IWUSR, + 'x':stat.S_IXUSR + }, + 'g':{ + 'r':stat.S_IRGRP, + 'w':stat.S_IWGRP, + 'x':stat.S_IXGRP + }, + 'o':{ + 'r':stat.S_IROTH, + 'w':stat.S_IWOTH, + 'x':stat.S_IXOTH + } +} + +def chmod_func(dest, mode): + import SCons.Util + from string import digits + SCons.Node.FS.invalidate_node_memos(dest) + if not SCons.Util.is_List(dest): + dest = [dest] + if SCons.Util.is_String(mode) and not 0 in [i in digits for i in mode]: + mode = int(mode, 8) + if not SCons.Util.is_String(mode): + for element in dest: + os.chmod(str(element), mode) + else: + mode = str(mode) + for operation in mode.split(","): + if "=" in operation: + operator = "=" + elif "+" in operation: + operator = "+" + elif "-" in operation: + operator = "-" + else: + raise SyntaxError("Could not find +, - or =") + operation_list = operation.split(operator) + if len(operation_list) != 2: + raise SyntaxError("More than one operator found") + user = operation_list[0].strip().replace("a", "ugo") + permission = operation_list[1].strip() + new_perm = 0 + for u in user: + for p in permission: + try: + new_perm = new_perm | permission_dic[u][p] + except KeyError: + raise SyntaxError("Unrecognized user or permission format") + for element in dest: + curr_perm = os.stat(str(element)).st_mode + if operator == "=": + os.chmod(str(element), new_perm) + elif operator == "+": + os.chmod(str(element), curr_perm | new_perm) + elif operator == "-": + os.chmod(str(element), curr_perm & ~new_perm) + +def chmod_strfunc(dest, mode): + import SCons.Util + if not SCons.Util.is_String(mode): + return 'Chmod(%s, 0%o)' % (get_paths_str(dest), mode) + else: + return 'Chmod(%s, "%s")' % (get_paths_str(dest), str(mode)) + +Chmod = ActionFactory(chmod_func, chmod_strfunc) + +def copy_func(dest, src, symlinks=True): + """ + If symlinks (is true), then a symbolic link will be + shallow copied and recreated as a symbolic link; otherwise, copying + a symbolic link will be equivalent to copying the symbolic link's + final target regardless of symbolic link depth. + """ + + dest = str(dest) + src = str(src) + + SCons.Node.FS.invalidate_node_memos(dest) + if SCons.Util.is_List(src) and os.path.isdir(dest): + for file in src: + shutil.copy2(file, dest) + return 0 + elif os.path.islink(src): + if symlinks: + return os.symlink(os.readlink(src), dest) + else: + return copy_func(dest, os.path.realpath(src)) + elif os.path.isfile(src): + shutil.copy2(src, dest) + return 0 + else: + shutil.copytree(src, dest, symlinks) + # copytree returns None in python2 and destination string in python3 + # A error is raised in both cases, so we can just return 0 for success + return 0 + +Copy = ActionFactory( + copy_func, + lambda dest, src, symlinks=True: 'Copy("%s", "%s")' % (dest, src) +) + +def delete_func(dest, must_exist=0): + SCons.Node.FS.invalidate_node_memos(dest) + if not SCons.Util.is_List(dest): + dest = [dest] + for entry in dest: + entry = str(entry) + # os.path.exists returns False with broken links that exist + entry_exists = os.path.exists(entry) or os.path.islink(entry) + if not entry_exists and not must_exist: + continue + # os.path.isdir returns True when entry is a link to a dir + if os.path.isdir(entry) and not os.path.islink(entry): + shutil.rmtree(entry, 1) + continue + os.unlink(entry) + +def delete_strfunc(dest, must_exist=0): + return 'Delete(%s)' % get_paths_str(dest) + +Delete = ActionFactory(delete_func, delete_strfunc) + +def mkdir_func(dest): + SCons.Node.FS.invalidate_node_memos(dest) + if not SCons.Util.is_List(dest): + dest = [dest] + for entry in dest: + try: + os.makedirs(str(entry)) + except os.error as e: + p = str(entry) + if (e.args[0] == errno.EEXIST or + (sys.platform=='win32' and e.args[0]==183)) \ + and os.path.isdir(str(entry)): + pass # not an error if already exists + else: + raise + +Mkdir = ActionFactory(mkdir_func, + lambda dir: 'Mkdir(%s)' % get_paths_str(dir)) + +def move_func(dest, src): + SCons.Node.FS.invalidate_node_memos(dest) + SCons.Node.FS.invalidate_node_memos(src) + shutil.move(src, dest) + +Move = ActionFactory(move_func, + lambda dest, src: 'Move("%s", "%s")' % (dest, src), + convert=str) + +def touch_func(dest): + SCons.Node.FS.invalidate_node_memos(dest) + if not SCons.Util.is_List(dest): + dest = [dest] + for file in dest: + file = str(file) + mtime = int(time.time()) + if os.path.exists(file): + atime = os.path.getatime(file) + else: + with open(file, 'w'): + atime = mtime + os.utime(file, (atime, mtime)) + +Touch = ActionFactory(touch_func, + lambda file: 'Touch(%s)' % get_paths_str(file)) + +# Internal utility functions + + +def _concat(prefix, list, suffix, env, f=lambda x: x, target=None, source=None): + """ + Creates a new list from 'list' by first interpolating each element + in the list using the 'env' dictionary and then calling f on the + list, and finally calling _concat_ixes to concatenate 'prefix' and + 'suffix' onto each element of the list. + """ + if not list: + return list + + l = f(SCons.PathList.PathList(list).subst_path(env, target, source)) + if l is not None: + list = l + + return _concat_ixes(prefix, list, suffix, env) + + +def _concat_ixes(prefix, list, suffix, env): + """ + Creates a new list from 'list' by concatenating the 'prefix' and + 'suffix' arguments onto each element of the list. A trailing space + on 'prefix' or leading space on 'suffix' will cause them to be put + into separate list elements rather than being concatenated. + """ + + result = [] + + # ensure that prefix and suffix are strings + prefix = str(env.subst(prefix, SCons.Subst.SUBST_RAW)) + suffix = str(env.subst(suffix, SCons.Subst.SUBST_RAW)) + + for x in list: + if isinstance(x, SCons.Node.FS.File): + result.append(x) + continue + x = str(x) + if x: + + if prefix: + if prefix[-1] == ' ': + result.append(prefix[:-1]) + elif x[:len(prefix)] != prefix: + x = prefix + x + + result.append(x) + + if suffix: + if suffix[0] == ' ': + result.append(suffix[1:]) + elif x[-len(suffix):] != suffix: + result[-1] = result[-1]+suffix + + return result + + +def _stripixes(prefix, itms, suffix, stripprefixes, stripsuffixes, env, c=None): + """ + This is a wrapper around _concat()/_concat_ixes() that checks for + the existence of prefixes or suffixes on list items and strips them + where it finds them. This is used by tools (like the GNU linker) + that need to turn something like 'libfoo.a' into '-lfoo'. + """ + + if not itms: + return itms + + if not callable(c): + env_c = env['_concat'] + if env_c != _concat and callable(env_c): + # There's a custom _concat() method in the construction + # environment, and we've allowed people to set that in + # the past (see test/custom-concat.py), so preserve the + # backwards compatibility. + c = env_c + else: + c = _concat_ixes + + stripprefixes = list(map(env.subst, SCons.Util.flatten(stripprefixes))) + stripsuffixes = list(map(env.subst, SCons.Util.flatten(stripsuffixes))) + + stripped = [] + for l in SCons.PathList.PathList(itms).subst_path(env, None, None): + if isinstance(l, SCons.Node.FS.File): + stripped.append(l) + continue + + if not SCons.Util.is_String(l): + l = str(l) + + for stripprefix in stripprefixes: + lsp = len(stripprefix) + if l[:lsp] == stripprefix: + l = l[lsp:] + # Do not strip more than one prefix + break + + for stripsuffix in stripsuffixes: + lss = len(stripsuffix) + if l[-lss:] == stripsuffix: + l = l[:-lss] + # Do not strip more than one suffix + break + + stripped.append(l) + + return c(prefix, stripped, suffix, env) + +def processDefines(defs): + """process defines, resolving strings, lists, dictionaries, into a list of + strings + """ + if SCons.Util.is_List(defs): + l = [] + for d in defs: + if d is None: + continue + elif SCons.Util.is_List(d) or isinstance(d, tuple): + if len(d) >= 2: + l.append(str(d[0]) + '=' + str(d[1])) + else: + l.append(str(d[0])) + elif SCons.Util.is_Dict(d): + for macro,value in d.items(): + if value is not None: + l.append(str(macro) + '=' + str(value)) + else: + l.append(str(macro)) + elif SCons.Util.is_String(d): + l.append(str(d)) + else: + raise SCons.Errors.UserError("DEFINE %s is not a list, dict, string or None."%repr(d)) + elif SCons.Util.is_Dict(defs): + # The items in a dictionary are stored in random order, but + # if the order of the command-line options changes from + # invocation to invocation, then the signature of the command + # line will change and we'll get random unnecessary rebuilds. + # Consequently, we have to sort the keys to ensure a + # consistent order... + l = [] + for k,v in sorted(defs.items()): + if v is None: + l.append(str(k)) + else: + l.append(str(k) + '=' + str(v)) + else: + l = [str(defs)] + return l + + +def _defines(prefix, defs, suffix, env, c=_concat_ixes): + """A wrapper around _concat_ixes that turns a list or string + into a list of C preprocessor command-line definitions. + """ + + return c(prefix, env.subst_path(processDefines(defs)), suffix, env) + + +class NullCmdGenerator(object): + """This is a callable class that can be used in place of other + command generators if you don't want them to do anything. + + The __call__ method for this class simply returns the thing + you instantiated it with. + + Example usage: + env["DO_NOTHING"] = NullCmdGenerator + env["LINKCOM"] = "${DO_NOTHING('$LINK $SOURCES $TARGET')}" + """ + + def __init__(self, cmd): + self.cmd = cmd + + def __call__(self, target, source, env, for_signature=None): + return self.cmd + + +class Variable_Method_Caller(object): + """A class for finding a construction variable on the stack and + calling one of its methods. + + We use this to support "construction variables" in our string + eval()s that actually stand in for methods--specifically, use + of "RDirs" in call to _concat that should actually execute the + "TARGET.RDirs" method. (We used to support this by creating a little + "build dictionary" that mapped RDirs to the method, but this got in + the way of Memoizing construction environments, because we had to + create new environment objects to hold the variables.) + """ + def __init__(self, variable, method): + self.variable = variable + self.method = method + def __call__(self, *args, **kw): + try: 1//0 + except ZeroDivisionError: + # Don't start iterating with the current stack-frame to + # prevent creating reference cycles (f_back is safe). + frame = sys.exc_info()[2].tb_frame.f_back + variable = self.variable + while frame: + if variable in frame.f_locals: + v = frame.f_locals[variable] + if v: + method = getattr(v, self.method) + return method(*args, **kw) + frame = frame.f_back + return None + +# if $version_var is not empty, returns env[flags_var], otherwise returns None +def __libversionflags(env, version_var, flags_var): + try: + if env.subst('$'+version_var): + return env[flags_var] + except KeyError: + pass + return None + +ConstructionEnvironment = { + 'BUILDERS' : {}, + 'SCANNERS' : [ SCons.Tool.SourceFileScanner ], + 'CONFIGUREDIR' : '#/.sconf_temp', + 'CONFIGURELOG' : '#/config.log', + 'CPPSUFFIXES' : SCons.Tool.CSuffixes, + 'DSUFFIXES' : SCons.Tool.DSuffixes, + 'ENV' : {}, + 'IDLSUFFIXES' : SCons.Tool.IDLSuffixes, + '_concat' : _concat, + '_defines' : _defines, + '_stripixes' : _stripixes, + '_LIBFLAGS' : '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}', + '_LIBDIRFLAGS' : '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)', + '_CPPINCFLAGS' : '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)', + '_CPPDEFFLAGS' : '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}', + + '__libversionflags' : __libversionflags, + '__SHLIBVERSIONFLAGS' : '${__libversionflags(__env__,"SHLIBVERSION","_SHLIBVERSIONFLAGS")}', + '__LDMODULEVERSIONFLAGS' : '${__libversionflags(__env__,"LDMODULEVERSION","_LDMODULEVERSIONFLAGS")}', + '__DSHLIBVERSIONFLAGS' : '${__libversionflags(__env__,"DSHLIBVERSION","_DSHLIBVERSIONFLAGS")}', + + 'TEMPFILE' : NullCmdGenerator, + 'Dir' : Variable_Method_Caller('TARGET', 'Dir'), + 'Dirs' : Variable_Method_Caller('TARGET', 'Dirs'), + 'File' : Variable_Method_Caller('TARGET', 'File'), + 'RDirs' : Variable_Method_Caller('TARGET', 'RDirs'), +} + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Environment.py b/tools/scons/scons-local-3.0.5/SCons/Environment.py new file mode 100755 index 0000000000..0fcd6178e6 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Environment.py @@ -0,0 +1,2444 @@ +"""SCons.Environment + +Base class for construction Environments. These are +the primary objects used to communicate dependency and +construction information to the build engine. + +Keyword arguments supplied when the construction Environment +is created are construction variables used to initialize the +Environment +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +__revision__ = "src/engine/SCons/Environment.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + + +import copy +import os +import sys +import re +import shlex +from collections import UserDict + +import SCons.Action +import SCons.Builder +import SCons.Debug +from SCons.Debug import logInstanceCreation +import SCons.Defaults +import SCons.Errors +import SCons.Memoize +import SCons.Node +import SCons.Node.Alias +import SCons.Node.FS +import SCons.Node.Python +import SCons.Platform +import SCons.SConf +import SCons.SConsign +import SCons.Subst +import SCons.Tool +import SCons.Util +import SCons.Warnings + +class _Null(object): + pass + +_null = _Null + +_warn_copy_deprecated = True +_warn_source_signatures_deprecated = True +_warn_target_signatures_deprecated = True + +CleanTargets = {} +CalculatorArgs = {} + +semi_deepcopy = SCons.Util.semi_deepcopy +semi_deepcopy_dict = SCons.Util.semi_deepcopy_dict + +# Pull UserError into the global name space for the benefit of +# Environment().SourceSignatures(), which has some import statements +# which seem to mess up its ability to reference SCons directly. +UserError = SCons.Errors.UserError + +def alias_builder(env, target, source): + pass + +AliasBuilder = SCons.Builder.Builder(action = alias_builder, + target_factory = SCons.Node.Alias.default_ans.Alias, + source_factory = SCons.Node.FS.Entry, + multi = 1, + is_explicit = None, + name='AliasBuilder') + +def apply_tools(env, tools, toolpath): + # Store the toolpath in the Environment. + if toolpath is not None: + env['toolpath'] = toolpath + + if not tools: + return + # Filter out null tools from the list. + for tool in [_f for _f in tools if _f]: + if SCons.Util.is_List(tool) or isinstance(tool, tuple): + toolname = tool[0] + toolargs = tool[1] # should be a dict of kw args + tool = env.Tool(toolname, **toolargs) + else: + env.Tool(tool) + +# These names are (or will be) controlled by SCons; users should never +# set or override them. This warning can optionally be turned off, +# but scons will still ignore the illegal variable names even if it's off. +reserved_construction_var_names = [ + 'CHANGED_SOURCES', + 'CHANGED_TARGETS', + 'SOURCE', + 'SOURCES', + 'TARGET', + 'TARGETS', + 'UNCHANGED_SOURCES', + 'UNCHANGED_TARGETS', +] + +future_reserved_construction_var_names = [ + #'HOST_OS', + #'HOST_ARCH', + #'HOST_CPU', + ] + +def copy_non_reserved_keywords(dict): + result = semi_deepcopy(dict) + for k in list(result.keys()): + if k in reserved_construction_var_names: + msg = "Ignoring attempt to set reserved variable `$%s'" + SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning, msg % k) + del result[k] + return result + +def _set_reserved(env, key, value): + msg = "Ignoring attempt to set reserved variable `$%s'" + SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning, msg % key) + +def _set_future_reserved(env, key, value): + env._dict[key] = value + msg = "`$%s' will be reserved in a future release and setting it will become ignored" + SCons.Warnings.warn(SCons.Warnings.FutureReservedVariableWarning, msg % key) + +def _set_BUILDERS(env, key, value): + try: + bd = env._dict[key] + for k in list(bd.keys()): + del bd[k] + except KeyError: + bd = BuilderDict(bd, env) + env._dict[key] = bd + for k, v in value.items(): + if not SCons.Builder.is_a_Builder(v): + raise SCons.Errors.UserError('%s is not a Builder.' % repr(v)) + bd.update(value) + +def _del_SCANNERS(env, key): + del env._dict[key] + env.scanner_map_delete() + +def _set_SCANNERS(env, key, value): + env._dict[key] = value + env.scanner_map_delete() + +def _delete_duplicates(l, keep_last): + """Delete duplicates from a sequence, keeping the first or last.""" + seen=set() + result=[] + if keep_last: # reverse in & out, then keep first + l.reverse() + for i in l: + try: + if i not in seen: + result.append(i) + seen.add(i) + except TypeError: + # probably unhashable. Just keep it. + result.append(i) + if keep_last: + result.reverse() + return result + + + +# The following is partly based on code in a comment added by Peter +# Shannon at the following page (there called the "transplant" class): +# +# ASPN : Python Cookbook : Dynamically added methods to a class +# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81732 +# +# We had independently been using the idiom as BuilderWrapper, but +# factoring out the common parts into this base class, and making +# BuilderWrapper a subclass that overrides __call__() to enforce specific +# Builder calling conventions, simplified some of our higher-layer code. + +class MethodWrapper(object): + """ + A generic Wrapper class that associates a method (which can + actually be any callable) with an object. As part of creating this + MethodWrapper object an attribute with the specified (by default, + the name of the supplied method) is added to the underlying object. + When that new "method" is called, our __call__() method adds the + object as the first argument, simulating the Python behavior of + supplying "self" on method calls. + + We hang on to the name by which the method was added to the underlying + base class so that we can provide a method to "clone" ourselves onto + a new underlying object being copied (without which we wouldn't need + to save that info). + """ + def __init__(self, object, method, name=None): + if name is None: + name = method.__name__ + self.object = object + self.method = method + self.name = name + setattr(self.object, name, self) + + def __call__(self, *args, **kwargs): + nargs = (self.object,) + args + return self.method(*nargs, **kwargs) + + def clone(self, new_object): + """ + Returns an object that re-binds the underlying "method" to + the specified new object. + """ + return self.__class__(new_object, self.method, self.name) + +class BuilderWrapper(MethodWrapper): + """ + A MethodWrapper subclass that that associates an environment with + a Builder. + + This mainly exists to wrap the __call__() function so that all calls + to Builders can have their argument lists massaged in the same way + (treat a lone argument as the source, treat two arguments as target + then source, make sure both target and source are lists) without + having to have cut-and-paste code to do it. + + As a bit of obsessive backwards compatibility, we also intercept + attempts to get or set the "env" or "builder" attributes, which were + the names we used before we put the common functionality into the + MethodWrapper base class. We'll keep this around for a while in case + people shipped Tool modules that reached into the wrapper (like the + Tool/qt.py module does, or did). There shouldn't be a lot attribute + fetching or setting on these, so a little extra work shouldn't hurt. + """ + def __call__(self, target=None, source=_null, *args, **kw): + if source is _null: + source = target + target = None + if target is not None and not SCons.Util.is_List(target): + target = [target] + if source is not None and not SCons.Util.is_List(source): + source = [source] + return MethodWrapper.__call__(self, target, source, *args, **kw) + + def __repr__(self): + return '' % repr(self.name) + + def __str__(self): + return self.__repr__() + + def __getattr__(self, name): + if name == 'env': + return self.object + elif name == 'builder': + return self.method + else: + raise AttributeError(name) + + def __setattr__(self, name, value): + if name == 'env': + self.object = value + elif name == 'builder': + self.method = value + else: + self.__dict__[name] = value + + # This allows a Builder to be executed directly + # through the Environment to which it's attached. + # In practice, we shouldn't need this, because + # builders actually get executed through a Node. + # But we do have a unit test for this, and can't + # yet rule out that it would be useful in the + # future, so leave it for now. + #def execute(self, **kw): + # kw['env'] = self.env + # self.builder.execute(**kw) + +class BuilderDict(UserDict): + """This is a dictionary-like class used by an Environment to hold + the Builders. We need to do this because every time someone changes + the Builders in the Environment's BUILDERS dictionary, we must + update the Environment's attributes.""" + def __init__(self, dict, env): + # Set self.env before calling the superclass initialization, + # because it will end up calling our other methods, which will + # need to point the values in this dictionary to self.env. + self.env = env + UserDict.__init__(self, dict) + + def __semi_deepcopy__(self): + # These cannot be copied since they would both modify the same builder object, and indeed + # just copying would modify the original builder + raise TypeError( 'cannot semi_deepcopy a BuilderDict' ) + + def __setitem__(self, item, val): + try: + method = getattr(self.env, item).method + except AttributeError: + pass + else: + self.env.RemoveMethod(method) + UserDict.__setitem__(self, item, val) + BuilderWrapper(self.env, val, item) + + def __delitem__(self, item): + UserDict.__delitem__(self, item) + delattr(self.env, item) + + def update(self, dict): + for i, v in dict.items(): + self.__setitem__(i, v) + + + +_is_valid_var = re.compile(r'[_a-zA-Z]\w*$') + +def is_valid_construction_var(varstr): + """Return if the specified string is a legitimate construction + variable. + """ + return _is_valid_var.match(varstr) + + + +class SubstitutionEnvironment(object): + """Base class for different flavors of construction environments. + + This class contains a minimal set of methods that handle construction + variable expansion and conversion of strings to Nodes, which may or + may not be actually useful as a stand-alone class. Which methods + ended up in this class is pretty arbitrary right now. They're + basically the ones which we've empirically determined are common to + the different construction environment subclasses, and most of the + others that use or touch the underlying dictionary of construction + variables. + + Eventually, this class should contain all the methods that we + determine are necessary for a "minimal" interface to the build engine. + A full "native Python" SCons environment has gotten pretty heavyweight + with all of the methods and Tools and construction variables we've + jammed in there, so it would be nice to have a lighter weight + alternative for interfaces that don't need all of the bells and + whistles. (At some point, we'll also probably rename this class + "Base," since that more reflects what we want this class to become, + but because we've released comments that tell people to subclass + Environment.Base to create their own flavors of construction + environment, we'll save that for a future refactoring when this + class actually becomes useful.) + """ + + def __init__(self, **kw): + """Initialization of an underlying SubstitutionEnvironment class. + """ + if SCons.Debug.track_instances: logInstanceCreation(self, 'Environment.SubstitutionEnvironment') + self.fs = SCons.Node.FS.get_default_fs() + self.ans = SCons.Node.Alias.default_ans + self.lookup_list = SCons.Node.arg2nodes_lookups + self._dict = kw.copy() + self._init_special() + self.added_methods = [] + #self._memo = {} + + def _init_special(self): + """Initial the dispatch tables for special handling of + special construction variables.""" + self._special_del = {} + self._special_del['SCANNERS'] = _del_SCANNERS + + self._special_set = {} + for key in reserved_construction_var_names: + self._special_set[key] = _set_reserved + for key in future_reserved_construction_var_names: + self._special_set[key] = _set_future_reserved + self._special_set['BUILDERS'] = _set_BUILDERS + self._special_set['SCANNERS'] = _set_SCANNERS + + # Freeze the keys of self._special_set in a list for use by + # methods that need to check. (Empirically, list scanning has + # gotten better than dict.has_key() in Python 2.5.) + self._special_set_keys = list(self._special_set.keys()) + + def __eq__(self, other): + return self._dict == other._dict + + def __delitem__(self, key): + special = self._special_del.get(key) + if special: + special(self, key) + else: + del self._dict[key] + + def __getitem__(self, key): + return self._dict[key] + + def __setitem__(self, key, value): + # This is heavily used. This implementation is the best we have + # according to the timings in bench/env.__setitem__.py. + # + # The "key in self._special_set_keys" test here seems to perform + # pretty well for the number of keys we have. A hard-coded + # list works a little better in Python 2.5, but that has the + # disadvantage of maybe getting out of sync if we ever add more + # variable names. Using self._special_set.has_key() works a + # little better in Python 2.4, but is worse than this test. + # So right now it seems like a good trade-off, but feel free to + # revisit this with bench/env.__setitem__.py as needed (and + # as newer versions of Python come out). + if key in self._special_set_keys: + self._special_set[key](self, key, value) + else: + # If we already have the entry, then it's obviously a valid + # key and we don't need to check. If we do check, using a + # global, pre-compiled regular expression directly is more + # efficient than calling another function or a method. + if key not in self._dict \ + and not _is_valid_var.match(key): + raise SCons.Errors.UserError("Illegal construction variable `%s'" % key) + self._dict[key] = value + + def get(self, key, default=None): + """Emulates the get() method of dictionaries.""" + return self._dict.get(key, default) + + def has_key(self, key): + return key in self._dict + + def __contains__(self, key): + return self._dict.__contains__(key) + + def items(self): + return list(self._dict.items()) + + def arg2nodes(self, args, node_factory=_null, lookup_list=_null, **kw): + if node_factory is _null: + node_factory = self.fs.File + if lookup_list is _null: + lookup_list = self.lookup_list + + if not args: + return [] + + args = SCons.Util.flatten(args) + + nodes = [] + for v in args: + if SCons.Util.is_String(v): + n = None + for l in lookup_list: + n = l(v) + if n is not None: + break + if n is not None: + if SCons.Util.is_String(n): + # n = self.subst(n, raw=1, **kw) + kw['raw'] = 1 + n = self.subst(n, **kw) + if node_factory: + n = node_factory(n) + if SCons.Util.is_List(n): + nodes.extend(n) + else: + nodes.append(n) + elif node_factory: + # v = node_factory(self.subst(v, raw=1, **kw)) + kw['raw'] = 1 + v = node_factory(self.subst(v, **kw)) + if SCons.Util.is_List(v): + nodes.extend(v) + else: + nodes.append(v) + else: + nodes.append(v) + + return nodes + + def gvars(self): + return self._dict + + def lvars(self): + return {} + + def subst(self, string, raw=0, target=None, source=None, conv=None, executor=None): + """Recursively interpolates construction variables from the + Environment into the specified string, returning the expanded + result. Construction variables are specified by a $ prefix + in the string and begin with an initial underscore or + alphabetic character followed by any number of underscores + or alphanumeric characters. The construction variable names + may be surrounded by curly braces to separate the name from + trailing characters. + """ + gvars = self.gvars() + lvars = self.lvars() + lvars['__env__'] = self + if executor: + lvars.update(executor.get_lvars()) + return SCons.Subst.scons_subst(string, self, raw, target, source, gvars, lvars, conv) + + def subst_kw(self, kw, raw=0, target=None, source=None): + nkw = {} + for k, v in kw.items(): + k = self.subst(k, raw, target, source) + if SCons.Util.is_String(v): + v = self.subst(v, raw, target, source) + nkw[k] = v + return nkw + + def subst_list(self, string, raw=0, target=None, source=None, conv=None, executor=None): + """Calls through to SCons.Subst.scons_subst_list(). See + the documentation for that function.""" + gvars = self.gvars() + lvars = self.lvars() + lvars['__env__'] = self + if executor: + lvars.update(executor.get_lvars()) + return SCons.Subst.scons_subst_list(string, self, raw, target, source, gvars, lvars, conv) + + def subst_path(self, path, target=None, source=None): + """Substitute a path list, turning EntryProxies into Nodes + and leaving Nodes (and other objects) as-is.""" + + if not SCons.Util.is_List(path): + path = [path] + + def s(obj): + """This is the "string conversion" routine that we have our + substitutions use to return Nodes, not strings. This relies + on the fact that an EntryProxy object has a get() method that + returns the underlying Node that it wraps, which is a bit of + architectural dependence that we might need to break or modify + in the future in response to additional requirements.""" + try: + get = obj.get + except AttributeError: + obj = SCons.Util.to_String_for_subst(obj) + else: + obj = get() + return obj + + r = [] + for p in path: + if SCons.Util.is_String(p): + p = self.subst(p, target=target, source=source, conv=s) + if SCons.Util.is_List(p): + if len(p) == 1: + p = p[0] + else: + # We have an object plus a string, or multiple + # objects that we need to smush together. No choice + # but to make them into a string. + p = ''.join(map(SCons.Util.to_String_for_subst, p)) + else: + p = s(p) + r.append(p) + return r + + subst_target_source = subst + + def backtick(self, command): + import subprocess + # common arguments + kw = { 'stdin' : 'devnull', + 'stdout' : subprocess.PIPE, + 'stderr' : subprocess.PIPE, + 'universal_newlines' : True, + } + # if the command is a list, assume it's been quoted + # othewise force a shell + if not SCons.Util.is_List(command): kw['shell'] = True + # run constructed command + p = SCons.Action._subproc(self, command, **kw) + out,err = p.communicate() + status = p.wait() + if err: + sys.stderr.write(u"" + err) + if status: + raise OSError("'%s' exited %d" % (command, status)) + return out + + def AddMethod(self, function, name=None): + """ + Adds the specified function as a method of this construction + environment with the specified name. If the name is omitted, + the default name is the name of the function itself. + """ + method = MethodWrapper(self, function, name) + self.added_methods.append(method) + + def RemoveMethod(self, function): + """ + Removes the specified function's MethodWrapper from the + added_methods list, so we don't re-bind it when making a clone. + """ + self.added_methods = [dm for dm in self.added_methods if not dm.method is function] + + def Override(self, overrides): + """ + Produce a modified environment whose variables are overridden by + the overrides dictionaries. "overrides" is a dictionary that + will override the variables of this environment. + + This function is much more efficient than Clone() or creating + a new Environment because it doesn't copy the construction + environment dictionary, it just wraps the underlying construction + environment, and doesn't even create a wrapper object if there + are no overrides. + """ + if not overrides: return self + o = copy_non_reserved_keywords(overrides) + if not o: return self + overrides = {} + merges = None + for key, value in o.items(): + if key == 'parse_flags': + merges = value + else: + overrides[key] = SCons.Subst.scons_subst_once(value, self, key) + env = OverrideEnvironment(self, overrides) + if merges: env.MergeFlags(merges) + return env + + def ParseFlags(self, *flags): + """ + Parse the set of flags and return a dict with the flags placed + in the appropriate entry. The flags are treated as a typical + set of command-line flags for a GNU-like toolchain and used to + populate the entries in the dict immediately below. If one of + the flag strings begins with a bang (exclamation mark), it is + assumed to be a command and the rest of the string is executed; + the result of that evaluation is then added to the dict. + """ + dict = { + 'ASFLAGS' : SCons.Util.CLVar(''), + 'CFLAGS' : SCons.Util.CLVar(''), + 'CCFLAGS' : SCons.Util.CLVar(''), + 'CXXFLAGS' : SCons.Util.CLVar(''), + 'CPPDEFINES' : [], + 'CPPFLAGS' : SCons.Util.CLVar(''), + 'CPPPATH' : [], + 'FRAMEWORKPATH' : SCons.Util.CLVar(''), + 'FRAMEWORKS' : SCons.Util.CLVar(''), + 'LIBPATH' : [], + 'LIBS' : [], + 'LINKFLAGS' : SCons.Util.CLVar(''), + 'RPATH' : [], + } + + def do_parse(arg): + # if arg is a sequence, recurse with each element + if not arg: + return + + if not SCons.Util.is_String(arg): + for t in arg: do_parse(t) + return + + # if arg is a command, execute it + if arg[0] == '!': + arg = self.backtick(arg[1:]) + + # utility function to deal with -D option + def append_define(name, dict = dict): + t = name.split('=') + if len(t) == 1: + dict['CPPDEFINES'].append(name) + else: + dict['CPPDEFINES'].append([t[0], '='.join(t[1:])]) + + # Loop through the flags and add them to the appropriate option. + # This tries to strike a balance between checking for all possible + # flags and keeping the logic to a finite size, so it doesn't + # check for some that don't occur often. It particular, if the + # flag is not known to occur in a config script and there's a way + # of passing the flag to the right place (by wrapping it in a -W + # flag, for example) we don't check for it. Note that most + # preprocessor options are not handled, since unhandled options + # are placed in CCFLAGS, so unless the preprocessor is invoked + # separately, these flags will still get to the preprocessor. + # Other options not currently handled: + # -iqoutedir (preprocessor search path) + # -u symbol (linker undefined symbol) + # -s (linker strip files) + # -static* (linker static binding) + # -shared* (linker dynamic binding) + # -symbolic (linker global binding) + # -R dir (deprecated linker rpath) + # IBM compilers may also accept -qframeworkdir=foo + + params = shlex.split(arg) + append_next_arg_to = None # for multi-word args + for arg in params: + if append_next_arg_to: + if append_next_arg_to == 'CPPDEFINES': + append_define(arg) + elif append_next_arg_to == '-include': + t = ('-include', self.fs.File(arg)) + dict['CCFLAGS'].append(t) + elif append_next_arg_to == '-isysroot': + t = ('-isysroot', arg) + dict['CCFLAGS'].append(t) + dict['LINKFLAGS'].append(t) + elif append_next_arg_to == '-isystem': + t = ('-isystem', arg) + dict['CCFLAGS'].append(t) + elif append_next_arg_to == '-arch': + t = ('-arch', arg) + dict['CCFLAGS'].append(t) + dict['LINKFLAGS'].append(t) + else: + dict[append_next_arg_to].append(arg) + append_next_arg_to = None + elif not arg[0] in ['-', '+']: + dict['LIBS'].append(self.fs.File(arg)) + elif arg == '-dylib_file': + dict['LINKFLAGS'].append(arg) + append_next_arg_to = 'LINKFLAGS' + elif arg[:2] == '-L': + if arg[2:]: + dict['LIBPATH'].append(arg[2:]) + else: + append_next_arg_to = 'LIBPATH' + elif arg[:2] == '-l': + if arg[2:]: + dict['LIBS'].append(arg[2:]) + else: + append_next_arg_to = 'LIBS' + elif arg[:2] == '-I': + if arg[2:]: + dict['CPPPATH'].append(arg[2:]) + else: + append_next_arg_to = 'CPPPATH' + elif arg[:4] == '-Wa,': + dict['ASFLAGS'].append(arg[4:]) + dict['CCFLAGS'].append(arg) + elif arg[:4] == '-Wl,': + if arg[:11] == '-Wl,-rpath=': + dict['RPATH'].append(arg[11:]) + elif arg[:7] == '-Wl,-R,': + dict['RPATH'].append(arg[7:]) + elif arg[:6] == '-Wl,-R': + dict['RPATH'].append(arg[6:]) + else: + dict['LINKFLAGS'].append(arg) + elif arg[:4] == '-Wp,': + dict['CPPFLAGS'].append(arg) + elif arg[:2] == '-D': + if arg[2:]: + append_define(arg[2:]) + else: + append_next_arg_to = 'CPPDEFINES' + elif arg == '-framework': + append_next_arg_to = 'FRAMEWORKS' + elif arg[:14] == '-frameworkdir=': + dict['FRAMEWORKPATH'].append(arg[14:]) + elif arg[:2] == '-F': + if arg[2:]: + dict['FRAMEWORKPATH'].append(arg[2:]) + else: + append_next_arg_to = 'FRAMEWORKPATH' + elif arg in ['-mno-cygwin', + '-pthread', + '-openmp', + '-fopenmp']: + dict['CCFLAGS'].append(arg) + dict['LINKFLAGS'].append(arg) + elif arg == '-mwindows': + dict['LINKFLAGS'].append(arg) + elif arg[:5] == '-std=': + if arg[5:].find('++')!=-1: + key='CXXFLAGS' + else: + key='CFLAGS' + dict[key].append(arg) + elif arg[0] == '+': + dict['CCFLAGS'].append(arg) + dict['LINKFLAGS'].append(arg) + elif arg in ['-include', '-isysroot', '-isystem', '-arch']: + append_next_arg_to = arg + else: + dict['CCFLAGS'].append(arg) + + for arg in flags: + do_parse(arg) + return dict + + def MergeFlags(self, args, unique=1, dict=None): + """ + Merge the dict in args into the construction variables of this + env, or the passed-in dict. If args is not a dict, it is + converted into a dict using ParseFlags. If unique is not set, + the flags are appended rather than merged. + """ + + if dict is None: + dict = self + if not SCons.Util.is_Dict(args): + args = self.ParseFlags(args) + if not unique: + self.Append(**args) + return self + for key, value in args.items(): + if not value: + continue + try: + orig = self[key] + except KeyError: + orig = value + else: + if not orig: + orig = value + elif value: + # Add orig and value. The logic here was lifted from + # part of env.Append() (see there for a lot of comments + # about the order in which things are tried) and is + # used mainly to handle coercion of strings to CLVar to + # "do the right thing" given (e.g.) an original CCFLAGS + # string variable like '-pipe -Wall'. + try: + orig = orig + value + except (KeyError, TypeError): + try: + add_to_orig = orig.append + except AttributeError: + value.insert(0, orig) + orig = value + else: + add_to_orig(value) + t = [] + if key[-4:] == 'PATH': + ### keep left-most occurence + for v in orig: + if v not in t: + t.append(v) + else: + ### keep right-most occurence + orig.reverse() + for v in orig: + if v not in t: + t.insert(0, v) + self[key] = t + return self + + +def default_decide_source(dependency, target, prev_ni): + f = SCons.Defaults.DefaultEnvironment().decide_source + return f(dependency, target, prev_ni) + +def default_decide_target(dependency, target, prev_ni): + f = SCons.Defaults.DefaultEnvironment().decide_target + return f(dependency, target, prev_ni) + +def default_copy_from_cache(src, dst): + f = SCons.Defaults.DefaultEnvironment().copy_from_cache + return f(src, dst) + +class Base(SubstitutionEnvironment): + """Base class for "real" construction Environments. These are the + primary objects used to communicate dependency and construction + information to the build engine. + + Keyword arguments supplied when the construction Environment + is created are construction variables used to initialize the + Environment. + """ + + ####################################################################### + # This is THE class for interacting with the SCons build engine, + # and it contains a lot of stuff, so we're going to try to keep this + # a little organized by grouping the methods. + ####################################################################### + + ####################################################################### + # Methods that make an Environment act like a dictionary. These have + # the expected standard names for Python mapping objects. Note that + # we don't actually make an Environment a subclass of UserDict for + # performance reasons. Note also that we only supply methods for + # dictionary functionality that we actually need and use. + ####################################################################### + + def __init__(self, + platform=None, + tools=None, + toolpath=None, + variables=None, + parse_flags = None, + **kw): + """ + Initialization of a basic SCons construction environment, + including setting up special construction variables like BUILDER, + PLATFORM, etc., and searching for and applying available Tools. + + Note that we do *not* call the underlying base class + (SubsitutionEnvironment) initialization, because we need to + initialize things in a very specific order that doesn't work + with the much simpler base class initialization. + """ + if SCons.Debug.track_instances: logInstanceCreation(self, 'Environment.Base') + self._memo = {} + self.fs = SCons.Node.FS.get_default_fs() + self.ans = SCons.Node.Alias.default_ans + self.lookup_list = SCons.Node.arg2nodes_lookups + self._dict = semi_deepcopy(SCons.Defaults.ConstructionEnvironment) + self._init_special() + self.added_methods = [] + + # We don't use AddMethod, or define these as methods in this + # class, because we *don't* want these functions to be bound + # methods. They need to operate independently so that the + # settings will work properly regardless of whether a given + # target ends up being built with a Base environment or an + # OverrideEnvironment or what have you. + self.decide_target = default_decide_target + self.decide_source = default_decide_source + + self.copy_from_cache = default_copy_from_cache + + self._dict['BUILDERS'] = BuilderDict(self._dict['BUILDERS'], self) + + if platform is None: + platform = self._dict.get('PLATFORM', None) + if platform is None: + platform = SCons.Platform.Platform() + if SCons.Util.is_String(platform): + platform = SCons.Platform.Platform(platform) + self._dict['PLATFORM'] = str(platform) + platform(self) + + self._dict['HOST_OS'] = self._dict.get('HOST_OS',None) + self._dict['HOST_ARCH'] = self._dict.get('HOST_ARCH',None) + + # Now set defaults for TARGET_{OS|ARCH} + self._dict['TARGET_OS'] = self._dict.get('TARGET_OS',None) + self._dict['TARGET_ARCH'] = self._dict.get('TARGET_ARCH',None) + + + # Apply the passed-in and customizable variables to the + # environment before calling the tools, because they may use + # some of them during initialization. + if 'options' in kw: + # Backwards compatibility: they may stll be using the + # old "options" keyword. + variables = kw['options'] + del kw['options'] + self.Replace(**kw) + keys = list(kw.keys()) + if variables: + keys = keys + list(variables.keys()) + variables.Update(self) + + save = {} + for k in keys: + try: + save[k] = self._dict[k] + except KeyError: + # No value may have been set if they tried to pass in a + # reserved variable name like TARGETS. + pass + + SCons.Tool.Initializers(self) + + if tools is None: + tools = self._dict.get('TOOLS', None) + if tools is None: + tools = ['default'] + apply_tools(self, tools, toolpath) + + # Now restore the passed-in and customized variables + # to the environment, since the values the user set explicitly + # should override any values set by the tools. + for key, val in save.items(): + self._dict[key] = val + + # Finally, apply any flags to be merged in + if parse_flags: self.MergeFlags(parse_flags) + + ####################################################################### + # Utility methods that are primarily for internal use by SCons. + # These begin with lower-case letters. + ####################################################################### + + def get_builder(self, name): + """Fetch the builder with the specified name from the environment. + """ + try: + return self._dict['BUILDERS'][name] + except KeyError: + return None + + def get_CacheDir(self): + try: + path = self._CacheDir_path + except AttributeError: + path = SCons.Defaults.DefaultEnvironment()._CacheDir_path + try: + if path == self._last_CacheDir_path: + return self._last_CacheDir + except AttributeError: + pass + cd = SCons.CacheDir.CacheDir(path) + self._last_CacheDir_path = path + self._last_CacheDir = cd + return cd + + def get_factory(self, factory, default='File'): + """Return a factory function for creating Nodes for this + construction environment. + """ + name = default + try: + is_node = issubclass(factory, SCons.Node.FS.Base) + except TypeError: + # The specified factory isn't a Node itself--it's + # most likely None, or possibly a callable. + pass + else: + if is_node: + # The specified factory is a Node (sub)class. Try to + # return the FS method that corresponds to the Node's + # name--that is, we return self.fs.Dir if they want a Dir, + # self.fs.File for a File, etc. + try: name = factory.__name__ + except AttributeError: pass + else: factory = None + if not factory: + # They passed us None, or we picked up a name from a specified + # class, so return the FS method. (Note that we *don't* + # use our own self.{Dir,File} methods because that would + # cause env.subst() to be called twice on the file name, + # interfering with files that have $$ in them.) + factory = getattr(self.fs, name) + return factory + + @SCons.Memoize.CountMethodCall + def _gsm(self): + try: + return self._memo['_gsm'] + except KeyError: + pass + + result = {} + + try: + scanners = self._dict['SCANNERS'] + except KeyError: + pass + else: + # Reverse the scanner list so that, if multiple scanners + # claim they can scan the same suffix, earlier scanners + # in the list will overwrite later scanners, so that + # the result looks like a "first match" to the user. + if not SCons.Util.is_List(scanners): + scanners = [scanners] + else: + scanners = scanners[:] # copy so reverse() doesn't mod original + scanners.reverse() + for scanner in scanners: + for k in scanner.get_skeys(self): + if k and self['PLATFORM'] == 'win32': + k = k.lower() + result[k] = scanner + + self._memo['_gsm'] = result + + return result + + def get_scanner(self, skey): + """Find the appropriate scanner given a key (usually a file suffix). + """ + if skey and self['PLATFORM'] == 'win32': + skey = skey.lower() + return self._gsm().get(skey) + + def scanner_map_delete(self, kw=None): + """Delete the cached scanner map (if we need to). + """ + try: + del self._memo['_gsm'] + except KeyError: + pass + + def _update(self, dict): + """Update an environment's values directly, bypassing the normal + checks that occur when users try to set items. + """ + self._dict.update(dict) + + def get_src_sig_type(self): + try: + return self.src_sig_type + except AttributeError: + t = SCons.Defaults.DefaultEnvironment().src_sig_type + self.src_sig_type = t + return t + + def get_tgt_sig_type(self): + try: + return self.tgt_sig_type + except AttributeError: + t = SCons.Defaults.DefaultEnvironment().tgt_sig_type + self.tgt_sig_type = t + return t + + ####################################################################### + # Public methods for manipulating an Environment. These begin with + # upper-case letters. The essential characteristic of methods in + # this section is that they do *not* have corresponding same-named + # global functions. For example, a stand-alone Append() function + # makes no sense, because Append() is all about appending values to + # an Environment's construction variables. + ####################################################################### + + def Append(self, **kw): + """Append values to existing construction variables + in an Environment. + """ + kw = copy_non_reserved_keywords(kw) + for key, val in kw.items(): + # It would be easier on the eyes to write this using + # "continue" statements whenever we finish processing an item, + # but Python 1.5.2 apparently doesn't let you use "continue" + # within try:-except: blocks, so we have to nest our code. + try: + if key == 'CPPDEFINES' and SCons.Util.is_String(self._dict[key]): + self._dict[key] = [self._dict[key]] + orig = self._dict[key] + except KeyError: + # No existing variable in the environment, so just set + # it to the new value. + if key == 'CPPDEFINES' and SCons.Util.is_String(val): + self._dict[key] = [val] + else: + self._dict[key] = val + else: + try: + # Check if the original looks like a dictionary. + # If it is, we can't just try adding the value because + # dictionaries don't have __add__() methods, and + # things like UserList will incorrectly coerce the + # original dict to a list (which we don't want). + update_dict = orig.update + except AttributeError: + try: + # Most straightforward: just try to add them + # together. This will work in most cases, when the + # original and new values are of compatible types. + self._dict[key] = orig + val + except (KeyError, TypeError): + try: + # Check if the original is a list. + add_to_orig = orig.append + except AttributeError: + # The original isn't a list, but the new + # value is (by process of elimination), + # so insert the original in the new value + # (if there's one to insert) and replace + # the variable with it. + if orig: + val.insert(0, orig) + self._dict[key] = val + else: + # The original is a list, so append the new + # value to it (if there's a value to append). + if val: + add_to_orig(val) + else: + # The original looks like a dictionary, so update it + # based on what we think the value looks like. + if SCons.Util.is_List(val): + if key == 'CPPDEFINES': + tmp = [] + for (k, v) in orig.items(): + if v is not None: + tmp.append((k, v)) + else: + tmp.append((k,)) + orig = tmp + orig += val + self._dict[key] = orig + else: + for v in val: + orig[v] = None + else: + try: + update_dict(val) + except (AttributeError, TypeError, ValueError): + if SCons.Util.is_Dict(val): + for k, v in val.items(): + orig[k] = v + else: + orig[val] = None + self.scanner_map_delete(kw) + + # allow Dirs and strings beginning with # for top-relative + # Note this uses the current env's fs (in self). + def _canonicalize(self, path): + if not SCons.Util.is_String(path): # typically a Dir + path = str(path) + if path and path[0] == '#': + path = str(self.fs.Dir(path)) + return path + + def AppendENVPath(self, name, newpath, envname = 'ENV', + sep = os.pathsep, delete_existing=0): + """Append path elements to the path 'name' in the 'ENV' + dictionary for this environment. Will only add any particular + path once, and will normpath and normcase all paths to help + assure this. This can also handle the case where the env + variable is a list instead of a string. + + If delete_existing is 0, a newpath which is already in the path + will not be moved to the end (it will be left where it is). + """ + + orig = '' + if envname in self._dict and name in self._dict[envname]: + orig = self._dict[envname][name] + + nv = SCons.Util.AppendPath(orig, newpath, sep, delete_existing, + canonicalize=self._canonicalize) + + if envname not in self._dict: + self._dict[envname] = {} + + self._dict[envname][name] = nv + + def AppendUnique(self, delete_existing=0, **kw): + """Append values to existing construction variables + in an Environment, if they're not already there. + If delete_existing is 1, removes existing values first, so + values move to end. + """ + kw = copy_non_reserved_keywords(kw) + for key, val in kw.items(): + if SCons.Util.is_List(val): + val = _delete_duplicates(val, delete_existing) + if key not in self._dict or self._dict[key] in ('', None): + self._dict[key] = val + elif SCons.Util.is_Dict(self._dict[key]) and \ + SCons.Util.is_Dict(val): + self._dict[key].update(val) + elif SCons.Util.is_List(val): + dk = self._dict[key] + if key == 'CPPDEFINES': + tmp = [] + for i in val: + if SCons.Util.is_List(i): + if len(i) >= 2: + tmp.append((i[0], i[1])) + else: + tmp.append((i[0],)) + elif SCons.Util.is_Tuple(i): + tmp.append(i) + else: + tmp.append((i,)) + val = tmp + # Construct a list of (key, value) tuples. + if SCons.Util.is_Dict(dk): + tmp = [] + for (k, v) in dk.items(): + if v is not None: + tmp.append((k, v)) + else: + tmp.append((k,)) + dk = tmp + elif SCons.Util.is_String(dk): + dk = [(dk,)] + else: + tmp = [] + for i in dk: + if SCons.Util.is_List(i): + if len(i) >= 2: + tmp.append((i[0], i[1])) + else: + tmp.append((i[0],)) + elif SCons.Util.is_Tuple(i): + tmp.append(i) + else: + tmp.append((i,)) + dk = tmp + else: + if not SCons.Util.is_List(dk): + dk = [dk] + if delete_existing: + dk = [x for x in dk if x not in val] + else: + val = [x for x in val if x not in dk] + self._dict[key] = dk + val + else: + dk = self._dict[key] + if SCons.Util.is_List(dk): + if key == 'CPPDEFINES': + tmp = [] + for i in dk: + if SCons.Util.is_List(i): + if len(i) >= 2: + tmp.append((i[0], i[1])) + else: + tmp.append((i[0],)) + elif SCons.Util.is_Tuple(i): + tmp.append(i) + else: + tmp.append((i,)) + dk = tmp + # Construct a list of (key, value) tuples. + if SCons.Util.is_Dict(val): + tmp = [] + for (k, v) in val.items(): + if v is not None: + tmp.append((k, v)) + else: + tmp.append((k,)) + val = tmp + elif SCons.Util.is_String(val): + val = [(val,)] + if delete_existing: + dk = list(filter(lambda x, val=val: x not in val, dk)) + self._dict[key] = dk + val + else: + dk = [x for x in dk if x not in val] + self._dict[key] = dk + val + else: + # By elimination, val is not a list. Since dk is a + # list, wrap val in a list first. + if delete_existing: + dk = list(filter(lambda x, val=val: x not in val, dk)) + self._dict[key] = dk + [val] + else: + if not val in dk: + self._dict[key] = dk + [val] + else: + if key == 'CPPDEFINES': + if SCons.Util.is_String(dk): + dk = [dk] + elif SCons.Util.is_Dict(dk): + tmp = [] + for (k, v) in dk.items(): + if v is not None: + tmp.append((k, v)) + else: + tmp.append((k,)) + dk = tmp + if SCons.Util.is_String(val): + if val in dk: + val = [] + else: + val = [val] + elif SCons.Util.is_Dict(val): + tmp = [] + for i,j in val.items(): + if j is not None: + tmp.append((i,j)) + else: + tmp.append(i) + val = tmp + if delete_existing: + dk = [x for x in dk if x not in val] + self._dict[key] = dk + val + self.scanner_map_delete(kw) + + def Clone(self, tools=[], toolpath=None, parse_flags = None, **kw): + """Return a copy of a construction Environment. The + copy is like a Python "deep copy"--that is, independent + copies are made recursively of each objects--except that + a reference is copied when an object is not deep-copyable + (like a function). There are no references to any mutable + objects in the original Environment. + """ + + builders = self._dict.get('BUILDERS', {}) + + clone = copy.copy(self) + # BUILDERS is not safe to do a simple copy + clone._dict = semi_deepcopy_dict(self._dict, ['BUILDERS']) + clone._dict['BUILDERS'] = BuilderDict(builders, clone) + + # Check the methods added via AddMethod() and re-bind them to + # the cloned environment. Only do this if the attribute hasn't + # been overwritten by the user explicitly and still points to + # the added method. + clone.added_methods = [] + for mw in self.added_methods: + if mw == getattr(self, mw.name): + clone.added_methods.append(mw.clone(clone)) + + clone._memo = {} + + # Apply passed-in variables before the tools + # so the tools can use the new variables + kw = copy_non_reserved_keywords(kw) + new = {} + for key, value in kw.items(): + new[key] = SCons.Subst.scons_subst_once(value, self, key) + clone.Replace(**new) + + apply_tools(clone, tools, toolpath) + + # apply them again in case the tools overwrote them + clone.Replace(**new) + + # Finally, apply any flags to be merged in + if parse_flags: clone.MergeFlags(parse_flags) + + if SCons.Debug.track_instances: logInstanceCreation(self, 'Environment.EnvironmentClone') + return clone + + def Copy(self, *args, **kw): + global _warn_copy_deprecated + if _warn_copy_deprecated: + msg = "The env.Copy() method is deprecated; use the env.Clone() method instead." + SCons.Warnings.warn(SCons.Warnings.DeprecatedCopyWarning, msg) + _warn_copy_deprecated = False + return self.Clone(*args, **kw) + + def _changed_build(self, dependency, target, prev_ni): + if dependency.changed_state(target, prev_ni): + return 1 + return self.decide_source(dependency, target, prev_ni) + + def _changed_content(self, dependency, target, prev_ni): + return dependency.changed_content(target, prev_ni) + + def _changed_source(self, dependency, target, prev_ni): + target_env = dependency.get_build_env() + type = target_env.get_tgt_sig_type() + if type == 'source': + return target_env.decide_source(dependency, target, prev_ni) + else: + return target_env.decide_target(dependency, target, prev_ni) + + def _changed_timestamp_then_content(self, dependency, target, prev_ni): + return dependency.changed_timestamp_then_content(target, prev_ni) + + def _changed_timestamp_newer(self, dependency, target, prev_ni): + return dependency.changed_timestamp_newer(target, prev_ni) + + def _changed_timestamp_match(self, dependency, target, prev_ni): + return dependency.changed_timestamp_match(target, prev_ni) + + def _copy_from_cache(self, src, dst): + return self.fs.copy(src, dst) + + def _copy2_from_cache(self, src, dst): + return self.fs.copy2(src, dst) + + def Decider(self, function): + copy_function = self._copy2_from_cache + if function in ('MD5', 'content'): + if not SCons.Util.md5: + raise UserError("MD5 signatures are not available in this version of Python.") + function = self._changed_content + elif function == 'MD5-timestamp': + function = self._changed_timestamp_then_content + elif function in ('timestamp-newer', 'make'): + function = self._changed_timestamp_newer + copy_function = self._copy_from_cache + elif function == 'timestamp-match': + function = self._changed_timestamp_match + elif not callable(function): + raise UserError("Unknown Decider value %s" % repr(function)) + + # We don't use AddMethod because we don't want to turn the + # function, which only expects three arguments, into a bound + # method, which would add self as an initial, fourth argument. + self.decide_target = function + self.decide_source = function + + self.copy_from_cache = copy_function + + def Detect(self, progs): + """Return the first available program in progs. + """ + if not SCons.Util.is_List(progs): + progs = [ progs ] + for prog in progs: + path = self.WhereIs(prog) + if path: return prog + return None + + def Dictionary(self, *args): + if not args: + return self._dict + dlist = [self._dict[x] for x in args] + if len(dlist) == 1: + dlist = dlist[0] + return dlist + + def Dump(self, key = None): + """ + Using the standard Python pretty printer, return the contents of the + scons build environment as a string. + + If the key passed in is anything other than None, then that will + be used as an index into the build environment dictionary and + whatever is found there will be fed into the pretty printer. Note + that this key is case sensitive. + """ + import pprint + pp = pprint.PrettyPrinter(indent=2) + if key: + dict = self.Dictionary(key) + else: + dict = self.Dictionary() + return pp.pformat(dict) + + def FindIxes(self, paths, prefix, suffix): + """ + Search a list of paths for something that matches the prefix and suffix. + + paths - the list of paths or nodes. + prefix - construction variable for the prefix. + suffix - construction variable for the suffix. + """ + + suffix = self.subst('$'+suffix) + prefix = self.subst('$'+prefix) + + for path in paths: + dir,name = os.path.split(str(path)) + if name[:len(prefix)] == prefix and name[-len(suffix):] == suffix: + return path + + def ParseConfig(self, command, function=None, unique=1): + """ + Use the specified function to parse the output of the command + in order to modify the current environment. The 'command' can + be a string or a list of strings representing a command and + its arguments. 'Function' is an optional argument that takes + the environment, the output of the command, and the unique flag. + If no function is specified, MergeFlags, which treats the output + as the result of a typical 'X-config' command (i.e. gtk-config), + will merge the output into the appropriate variables. + """ + if function is None: + def parse_conf(env, cmd, unique=unique): + return env.MergeFlags(cmd, unique) + function = parse_conf + if SCons.Util.is_List(command): + command = ' '.join(command) + command = self.subst(command) + return function(self, self.backtick(command)) + + def ParseDepends(self, filename, must_exist=None, only_one=0): + """ + Parse a mkdep-style file for explicit dependencies. This is + completely abusable, and should be unnecessary in the "normal" + case of proper SCons configuration, but it may help make + the transition from a Make hierarchy easier for some people + to swallow. It can also be genuinely useful when using a tool + that can write a .d file, but for which writing a scanner would + be too complicated. + """ + filename = self.subst(filename) + try: + with open(filename, 'r') as fp: + lines = SCons.Util.LogicalLines(fp).readlines() + except IOError: + if must_exist: + raise + return + lines = [l for l in lines if l[0] != '#'] + tdlist = [] + for line in lines: + try: + target, depends = line.split(':', 1) + except (AttributeError, ValueError): + # Throws AttributeError if line isn't a string. Can throw + # ValueError if line doesn't split into two or more elements. + pass + else: + tdlist.append((target.split(), depends.split())) + if only_one: + targets = [] + for td in tdlist: + targets.extend(td[0]) + if len(targets) > 1: + raise SCons.Errors.UserError( + "More than one dependency target found in `%s': %s" + % (filename, targets)) + for target, depends in tdlist: + self.Depends(target, depends) + + def Platform(self, platform): + platform = self.subst(platform) + return SCons.Platform.Platform(platform)(self) + + def Prepend(self, **kw): + """Prepend values to existing construction variables + in an Environment. + """ + kw = copy_non_reserved_keywords(kw) + for key, val in kw.items(): + # It would be easier on the eyes to write this using + # "continue" statements whenever we finish processing an item, + # but Python 1.5.2 apparently doesn't let you use "continue" + # within try:-except: blocks, so we have to nest our code. + try: + orig = self._dict[key] + except KeyError: + # No existing variable in the environment, so just set + # it to the new value. + self._dict[key] = val + else: + try: + # Check if the original looks like a dictionary. + # If it is, we can't just try adding the value because + # dictionaries don't have __add__() methods, and + # things like UserList will incorrectly coerce the + # original dict to a list (which we don't want). + update_dict = orig.update + except AttributeError: + try: + # Most straightforward: just try to add them + # together. This will work in most cases, when the + # original and new values are of compatible types. + self._dict[key] = val + orig + except (KeyError, TypeError): + try: + # Check if the added value is a list. + add_to_val = val.append + except AttributeError: + # The added value isn't a list, but the + # original is (by process of elimination), + # so insert the the new value in the original + # (if there's one to insert). + if val: + orig.insert(0, val) + else: + # The added value is a list, so append + # the original to it (if there's a value + # to append). + if orig: + add_to_val(orig) + self._dict[key] = val + else: + # The original looks like a dictionary, so update it + # based on what we think the value looks like. + if SCons.Util.is_List(val): + for v in val: + orig[v] = None + else: + try: + update_dict(val) + except (AttributeError, TypeError, ValueError): + if SCons.Util.is_Dict(val): + for k, v in val.items(): + orig[k] = v + else: + orig[val] = None + self.scanner_map_delete(kw) + + def PrependENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep, + delete_existing=1): + """Prepend path elements to the path 'name' in the 'ENV' + dictionary for this environment. Will only add any particular + path once, and will normpath and normcase all paths to help + assure this. This can also handle the case where the env + variable is a list instead of a string. + + If delete_existing is 0, a newpath which is already in the path + will not be moved to the front (it will be left where it is). + """ + + orig = '' + if envname in self._dict and name in self._dict[envname]: + orig = self._dict[envname][name] + + nv = SCons.Util.PrependPath(orig, newpath, sep, delete_existing, + canonicalize=self._canonicalize) + + if envname not in self._dict: + self._dict[envname] = {} + + self._dict[envname][name] = nv + + def PrependUnique(self, delete_existing=0, **kw): + """Prepend values to existing construction variables + in an Environment, if they're not already there. + If delete_existing is 1, removes existing values first, so + values move to front. + """ + kw = copy_non_reserved_keywords(kw) + for key, val in kw.items(): + if SCons.Util.is_List(val): + val = _delete_duplicates(val, not delete_existing) + if key not in self._dict or self._dict[key] in ('', None): + self._dict[key] = val + elif SCons.Util.is_Dict(self._dict[key]) and \ + SCons.Util.is_Dict(val): + self._dict[key].update(val) + elif SCons.Util.is_List(val): + dk = self._dict[key] + if not SCons.Util.is_List(dk): + dk = [dk] + if delete_existing: + dk = [x for x in dk if x not in val] + else: + val = [x for x in val if x not in dk] + self._dict[key] = val + dk + else: + dk = self._dict[key] + if SCons.Util.is_List(dk): + # By elimination, val is not a list. Since dk is a + # list, wrap val in a list first. + if delete_existing: + dk = [x for x in dk if x not in val] + self._dict[key] = [val] + dk + else: + if not val in dk: + self._dict[key] = [val] + dk + else: + if delete_existing: + dk = [x for x in dk if x not in val] + self._dict[key] = val + dk + self.scanner_map_delete(kw) + + def Replace(self, **kw): + """Replace existing construction variables in an Environment + with new construction variables and/or values. + """ + try: + kwbd = kw['BUILDERS'] + except KeyError: + pass + else: + kwbd = BuilderDict(kwbd,self) + del kw['BUILDERS'] + self.__setitem__('BUILDERS', kwbd) + kw = copy_non_reserved_keywords(kw) + self._update(semi_deepcopy(kw)) + self.scanner_map_delete(kw) + + def ReplaceIxes(self, path, old_prefix, old_suffix, new_prefix, new_suffix): + """ + Replace old_prefix with new_prefix and old_suffix with new_suffix. + + env - Environment used to interpolate variables. + path - the path that will be modified. + old_prefix - construction variable for the old prefix. + old_suffix - construction variable for the old suffix. + new_prefix - construction variable for the new prefix. + new_suffix - construction variable for the new suffix. + """ + old_prefix = self.subst('$'+old_prefix) + old_suffix = self.subst('$'+old_suffix) + + new_prefix = self.subst('$'+new_prefix) + new_suffix = self.subst('$'+new_suffix) + + dir,name = os.path.split(str(path)) + if name[:len(old_prefix)] == old_prefix: + name = name[len(old_prefix):] + if name[-len(old_suffix):] == old_suffix: + name = name[:-len(old_suffix)] + return os.path.join(dir, new_prefix+name+new_suffix) + + def SetDefault(self, **kw): + for k in list(kw.keys()): + if k in self._dict: + del kw[k] + self.Replace(**kw) + + def _find_toolpath_dir(self, tp): + return self.fs.Dir(self.subst(tp)).srcnode().get_abspath() + + def Tool(self, tool, toolpath=None, **kw): + if SCons.Util.is_String(tool): + tool = self.subst(tool) + if toolpath is None: + toolpath = self.get('toolpath', []) + toolpath = list(map(self._find_toolpath_dir, toolpath)) + tool = SCons.Tool.Tool(tool, toolpath, **kw) + tool(self) + + def WhereIs(self, prog, path=None, pathext=None, reject=[]): + """Find prog in the path. + """ + if path is None: + try: + path = self['ENV']['PATH'] + except KeyError: + pass + elif SCons.Util.is_String(path): + path = self.subst(path) + if pathext is None: + try: + pathext = self['ENV']['PATHEXT'] + except KeyError: + pass + elif SCons.Util.is_String(pathext): + pathext = self.subst(pathext) + prog = SCons.Util.CLVar(self.subst(prog)) # support "program --with-args" + path = SCons.Util.WhereIs(prog[0], path, pathext, reject) + if path: return path + return None + + ####################################################################### + # Public methods for doing real "SCons stuff" (manipulating + # dependencies, setting attributes on targets, etc.). These begin + # with upper-case letters. The essential characteristic of methods + # in this section is that they all *should* have corresponding + # same-named global functions. + ####################################################################### + + def Action(self, *args, **kw): + def subst_string(a, self=self): + if SCons.Util.is_String(a): + a = self.subst(a) + return a + nargs = list(map(subst_string, args)) + nkw = self.subst_kw(kw) + return SCons.Action.Action(*nargs, **nkw) + + def AddPreAction(self, files, action): + nodes = self.arg2nodes(files, self.fs.Entry) + action = SCons.Action.Action(action) + uniq = {} + for executor in [n.get_executor() for n in nodes]: + uniq[executor] = 1 + for executor in list(uniq.keys()): + executor.add_pre_action(action) + return nodes + + def AddPostAction(self, files, action): + nodes = self.arg2nodes(files, self.fs.Entry) + action = SCons.Action.Action(action) + uniq = {} + for executor in [n.get_executor() for n in nodes]: + uniq[executor] = 1 + for executor in list(uniq.keys()): + executor.add_post_action(action) + return nodes + + def Alias(self, target, source=[], action=None, **kw): + tlist = self.arg2nodes(target, self.ans.Alias) + if not SCons.Util.is_List(source): + source = [source] + source = [_f for _f in source if _f] + + if not action: + if not source: + # There are no source files and no action, so just + # return a target list of classic Alias Nodes, without + # any builder. The externally visible effect is that + # this will make the wrapping Script.BuildTask class + # say that there's "Nothing to be done" for this Alias, + # instead of that it's "up to date." + return tlist + + # No action, but there are sources. Re-call all the target + # builders to add the sources to each target. + result = [] + for t in tlist: + bld = t.get_builder(AliasBuilder) + result.extend(bld(self, t, source)) + return result + + nkw = self.subst_kw(kw) + nkw.update({ + 'action' : SCons.Action.Action(action), + 'source_factory' : self.fs.Entry, + 'multi' : 1, + 'is_explicit' : None, + }) + bld = SCons.Builder.Builder(**nkw) + + # Apply the Builder separately to each target so that the Aliases + # stay separate. If we did one "normal" Builder call with the + # whole target list, then all of the target Aliases would be + # associated under a single Executor. + result = [] + for t in tlist: + # Calling the convert() method will cause a new Executor to be + # created from scratch, so we have to explicitly initialize + # it with the target's existing sources, plus our new ones, + # so nothing gets lost. + b = t.get_builder() + if b is None or b is AliasBuilder: + b = bld + else: + nkw['action'] = b.action + action + b = SCons.Builder.Builder(**nkw) + t.convert() + result.extend(b(self, t, t.sources + source)) + return result + + def AlwaysBuild(self, *targets): + tlist = [] + for t in targets: + tlist.extend(self.arg2nodes(t, self.fs.Entry)) + for t in tlist: + t.set_always_build() + return tlist + + def BuildDir(self, *args, **kw): + msg = """BuildDir() and the build_dir keyword have been deprecated;\n\tuse VariantDir() and the variant_dir keyword instead.""" + SCons.Warnings.warn(SCons.Warnings.DeprecatedBuildDirWarning, msg) + if 'build_dir' in kw: + kw['variant_dir'] = kw['build_dir'] + del kw['build_dir'] + return self.VariantDir(*args, **kw) + + def Builder(self, **kw): + nkw = self.subst_kw(kw) + return SCons.Builder.Builder(**nkw) + + def CacheDir(self, path): + import SCons.CacheDir + if path is not None: + path = self.subst(path) + self._CacheDir_path = path + + def Clean(self, targets, files): + global CleanTargets + tlist = self.arg2nodes(targets, self.fs.Entry) + flist = self.arg2nodes(files, self.fs.Entry) + for t in tlist: + try: + CleanTargets[t].extend(flist) + except KeyError: + CleanTargets[t] = flist + + def Configure(self, *args, **kw): + nargs = [self] + if args: + nargs = nargs + self.subst_list(args)[0] + nkw = self.subst_kw(kw) + nkw['_depth'] = kw.get('_depth', 0) + 1 + try: + nkw['custom_tests'] = self.subst_kw(nkw['custom_tests']) + except KeyError: + pass + return SCons.SConf.SConf(*nargs, **nkw) + + def Command(self, target, source, action, **kw): + """Builds the supplied target files from the supplied + source files using the supplied action. Action may + be any type that the Builder constructor will accept + for an action.""" + bkw = { + 'action' : action, + 'target_factory' : self.fs.Entry, + 'source_factory' : self.fs.Entry, + } + try: bkw['source_scanner'] = kw['source_scanner'] + except KeyError: pass + else: del kw['source_scanner'] + bld = SCons.Builder.Builder(**bkw) + return bld(self, target, source, **kw) + + def Depends(self, target, dependency): + """Explicity specify that 'target's depend on 'dependency'.""" + tlist = self.arg2nodes(target, self.fs.Entry) + dlist = self.arg2nodes(dependency, self.fs.Entry) + for t in tlist: + t.add_dependency(dlist) + return tlist + + def Dir(self, name, *args, **kw): + """ + """ + s = self.subst(name) + if SCons.Util.is_Sequence(s): + result=[] + for e in s: + result.append(self.fs.Dir(e, *args, **kw)) + return result + return self.fs.Dir(s, *args, **kw) + + def PyPackageDir(self, modulename): + s = self.subst(modulename) + if SCons.Util.is_Sequence(s): + result=[] + for e in s: + result.append(self.fs.PyPackageDir(e)) + return result + return self.fs.PyPackageDir(s) + + def NoClean(self, *targets): + """Tags a target so that it will not be cleaned by -c""" + tlist = [] + for t in targets: + tlist.extend(self.arg2nodes(t, self.fs.Entry)) + for t in tlist: + t.set_noclean() + return tlist + + def NoCache(self, *targets): + """Tags a target so that it will not be cached""" + tlist = [] + for t in targets: + tlist.extend(self.arg2nodes(t, self.fs.Entry)) + for t in tlist: + t.set_nocache() + return tlist + + def Entry(self, name, *args, **kw): + """ + """ + s = self.subst(name) + if SCons.Util.is_Sequence(s): + result=[] + for e in s: + result.append(self.fs.Entry(e, *args, **kw)) + return result + return self.fs.Entry(s, *args, **kw) + + def Environment(self, **kw): + return SCons.Environment.Environment(**self.subst_kw(kw)) + + def Execute(self, action, *args, **kw): + """Directly execute an action through an Environment + """ + action = self.Action(action, *args, **kw) + result = action([], [], self) + if isinstance(result, SCons.Errors.BuildError): + errstr = result.errstr + if result.filename: + errstr = result.filename + ': ' + errstr + sys.stderr.write("scons: *** %s\n" % errstr) + return result.status + else: + return result + + def File(self, name, *args, **kw): + """ + """ + s = self.subst(name) + if SCons.Util.is_Sequence(s): + result=[] + for e in s: + result.append(self.fs.File(e, *args, **kw)) + return result + return self.fs.File(s, *args, **kw) + + def FindFile(self, file, dirs): + file = self.subst(file) + nodes = self.arg2nodes(dirs, self.fs.Dir) + return SCons.Node.FS.find_file(file, tuple(nodes)) + + def Flatten(self, sequence): + return SCons.Util.flatten(sequence) + + def GetBuildPath(self, files): + result = list(map(str, self.arg2nodes(files, self.fs.Entry))) + if SCons.Util.is_List(files): + return result + else: + return result[0] + + def Glob(self, pattern, ondisk=True, source=False, strings=False, exclude=None): + return self.fs.Glob(self.subst(pattern), ondisk, source, strings, exclude) + + def Ignore(self, target, dependency): + """Ignore a dependency.""" + tlist = self.arg2nodes(target, self.fs.Entry) + dlist = self.arg2nodes(dependency, self.fs.Entry) + for t in tlist: + t.add_ignore(dlist) + return tlist + + def Literal(self, string): + return SCons.Subst.Literal(string) + + def Local(self, *targets): + ret = [] + for targ in targets: + if isinstance(targ, SCons.Node.Node): + targ.set_local() + ret.append(targ) + else: + for t in self.arg2nodes(targ, self.fs.Entry): + t.set_local() + ret.append(t) + return ret + + def Precious(self, *targets): + tlist = [] + for t in targets: + tlist.extend(self.arg2nodes(t, self.fs.Entry)) + for t in tlist: + t.set_precious() + return tlist + + def Pseudo(self, *targets): + tlist = [] + for t in targets: + tlist.extend(self.arg2nodes(t, self.fs.Entry)) + for t in tlist: + t.set_pseudo() + return tlist + + def Repository(self, *dirs, **kw): + dirs = self.arg2nodes(list(dirs), self.fs.Dir) + self.fs.Repository(*dirs, **kw) + + def Requires(self, target, prerequisite): + """Specify that 'prerequisite' must be built before 'target', + (but 'target' does not actually depend on 'prerequisite' + and need not be rebuilt if it changes).""" + tlist = self.arg2nodes(target, self.fs.Entry) + plist = self.arg2nodes(prerequisite, self.fs.Entry) + for t in tlist: + t.add_prerequisite(plist) + return tlist + + def Scanner(self, *args, **kw): + nargs = [] + for arg in args: + if SCons.Util.is_String(arg): + arg = self.subst(arg) + nargs.append(arg) + nkw = self.subst_kw(kw) + return SCons.Scanner.Base(*nargs, **nkw) + + def SConsignFile(self, name=".sconsign", dbm_module=None): + if name is not None: + name = self.subst(name) + if not os.path.isabs(name): + name = os.path.join(str(self.fs.SConstruct_dir), name) + if name: + name = os.path.normpath(name) + sconsign_dir = os.path.dirname(name) + if sconsign_dir and not os.path.exists(sconsign_dir): + self.Execute(SCons.Defaults.Mkdir(sconsign_dir)) + SCons.SConsign.File(name, dbm_module) + + def SideEffect(self, side_effect, target): + """Tell scons that side_effects are built as side + effects of building targets.""" + side_effects = self.arg2nodes(side_effect, self.fs.Entry) + targets = self.arg2nodes(target, self.fs.Entry) + + for side_effect in side_effects: + if side_effect.multiple_side_effect_has_builder(): + raise SCons.Errors.UserError("Multiple ways to build the same target were specified for: %s" % str(side_effect)) + side_effect.add_source(targets) + side_effect.side_effect = 1 + self.Precious(side_effect) + for target in targets: + target.side_effects.append(side_effect) + return side_effects + + def SourceCode(self, entry, builder): + """Arrange for a source code builder for (part of) a tree.""" + msg = """SourceCode() has been deprecated and there is no replacement. +\tIf you need this function, please contact scons-dev@scons.org""" + SCons.Warnings.warn(SCons.Warnings.DeprecatedSourceCodeWarning, msg) + entries = self.arg2nodes(entry, self.fs.Entry) + for entry in entries: + entry.set_src_builder(builder) + return entries + + def SourceSignatures(self, type): + global _warn_source_signatures_deprecated + if _warn_source_signatures_deprecated: + msg = "The env.SourceSignatures() method is deprecated;\n" + \ + "\tconvert your build to use the env.Decider() method instead." + SCons.Warnings.warn(SCons.Warnings.DeprecatedSourceSignaturesWarning, msg) + _warn_source_signatures_deprecated = False + type = self.subst(type) + self.src_sig_type = type + if type == 'MD5': + if not SCons.Util.md5: + raise UserError("MD5 signatures are not available in this version of Python.") + self.decide_source = self._changed_content + elif type == 'timestamp': + self.decide_source = self._changed_timestamp_match + else: + raise UserError("Unknown source signature type '%s'" % type) + + def Split(self, arg): + """This function converts a string or list into a list of strings + or Nodes. This makes things easier for users by allowing files to + be specified as a white-space separated list to be split. + + The input rules are: + - A single string containing names separated by spaces. These will be + split apart at the spaces. + - A single Node instance + - A list containing either strings or Node instances. Any strings + in the list are not split at spaces. + + In all cases, the function returns a list of Nodes and strings.""" + + if SCons.Util.is_List(arg): + return list(map(self.subst, arg)) + elif SCons.Util.is_String(arg): + return self.subst(arg).split() + else: + return [self.subst(arg)] + + def TargetSignatures(self, type): + global _warn_target_signatures_deprecated + if _warn_target_signatures_deprecated: + msg = "The env.TargetSignatures() method is deprecated;\n" + \ + "\tconvert your build to use the env.Decider() method instead." + SCons.Warnings.warn(SCons.Warnings.DeprecatedTargetSignaturesWarning, msg) + _warn_target_signatures_deprecated = False + type = self.subst(type) + self.tgt_sig_type = type + if type in ('MD5', 'content'): + if not SCons.Util.md5: + raise UserError("MD5 signatures are not available in this version of Python.") + self.decide_target = self._changed_content + elif type == 'timestamp': + self.decide_target = self._changed_timestamp_match + elif type == 'build': + self.decide_target = self._changed_build + elif type == 'source': + self.decide_target = self._changed_source + else: + raise UserError("Unknown target signature type '%s'"%type) + + def Value(self, value, built_value=None): + """ + """ + return SCons.Node.Python.Value(value, built_value) + + def VariantDir(self, variant_dir, src_dir, duplicate=1): + variant_dir = self.arg2nodes(variant_dir, self.fs.Dir)[0] + src_dir = self.arg2nodes(src_dir, self.fs.Dir)[0] + self.fs.VariantDir(variant_dir, src_dir, duplicate) + + def FindSourceFiles(self, node='.'): + """ returns a list of all source files. + """ + node = self.arg2nodes(node, self.fs.Entry)[0] + + sources = [] + def build_source(ss): + for s in ss: + if isinstance(s, SCons.Node.FS.Dir): + build_source(s.all_children()) + elif s.has_builder(): + build_source(s.sources) + elif isinstance(s.disambiguate(), SCons.Node.FS.File): + sources.append(s) + build_source(node.all_children()) + + def final_source(node): + while (node != node.srcnode()): + node = node.srcnode() + return node + sources = list(map(final_source, sources)) + # remove duplicates + return list(set(sources)) + + def FindInstalledFiles(self): + """ returns the list of all targets of the Install and InstallAs Builder. + """ + from SCons.Tool import install + if install._UNIQUE_INSTALLED_FILES is None: + install._UNIQUE_INSTALLED_FILES = SCons.Util.uniquer_hashables(install._INSTALLED_FILES) + return install._UNIQUE_INSTALLED_FILES + + +class OverrideEnvironment(Base): + """A proxy that overrides variables in a wrapped construction + environment by returning values from an overrides dictionary in + preference to values from the underlying subject environment. + + This is a lightweight (I hope) proxy that passes through most use of + attributes to the underlying Environment.Base class, but has just + enough additional methods defined to act like a real construction + environment with overridden values. It can wrap either a Base + construction environment, or another OverrideEnvironment, which + can in turn nest arbitrary OverrideEnvironments... + + Note that we do *not* call the underlying base class + (SubsitutionEnvironment) initialization, because we get most of those + from proxying the attributes of the subject construction environment. + But because we subclass SubstitutionEnvironment, this class also + has inherited arg2nodes() and subst*() methods; those methods can't + be proxied because they need *this* object's methods to fetch the + values from the overrides dictionary. + """ + + def __init__(self, subject, overrides={}): + if SCons.Debug.track_instances: logInstanceCreation(self, 'Environment.OverrideEnvironment') + self.__dict__['__subject'] = subject + self.__dict__['overrides'] = overrides + + # Methods that make this class act like a proxy. + def __getattr__(self, name): + return getattr(self.__dict__['__subject'], name) + def __setattr__(self, name, value): + setattr(self.__dict__['__subject'], name, value) + + # Methods that make this class act like a dictionary. + def __getitem__(self, key): + try: + return self.__dict__['overrides'][key] + except KeyError: + return self.__dict__['__subject'].__getitem__(key) + def __setitem__(self, key, value): + if not is_valid_construction_var(key): + raise SCons.Errors.UserError("Illegal construction variable `%s'" % key) + self.__dict__['overrides'][key] = value + def __delitem__(self, key): + try: + del self.__dict__['overrides'][key] + except KeyError: + deleted = 0 + else: + deleted = 1 + try: + result = self.__dict__['__subject'].__delitem__(key) + except KeyError: + if not deleted: + raise + result = None + return result + def get(self, key, default=None): + """Emulates the get() method of dictionaries.""" + try: + return self.__dict__['overrides'][key] + except KeyError: + return self.__dict__['__subject'].get(key, default) + def has_key(self, key): + try: + self.__dict__['overrides'][key] + return 1 + except KeyError: + return key in self.__dict__['__subject'] + def __contains__(self, key): + if self.__dict__['overrides'].__contains__(key): + return 1 + return self.__dict__['__subject'].__contains__(key) + def Dictionary(self): + """Emulates the items() method of dictionaries.""" + d = self.__dict__['__subject'].Dictionary().copy() + d.update(self.__dict__['overrides']) + return d + def items(self): + """Emulates the items() method of dictionaries.""" + return list(self.Dictionary().items()) + + # Overridden private construction environment methods. + def _update(self, dict): + """Update an environment's values directly, bypassing the normal + checks that occur when users try to set items. + """ + self.__dict__['overrides'].update(dict) + + def gvars(self): + return self.__dict__['__subject'].gvars() + + def lvars(self): + lvars = self.__dict__['__subject'].lvars() + lvars.update(self.__dict__['overrides']) + return lvars + + # Overridden public construction environment methods. + def Replace(self, **kw): + kw = copy_non_reserved_keywords(kw) + self.__dict__['overrides'].update(semi_deepcopy(kw)) + + +# The entry point that will be used by the external world +# to refer to a construction environment. This allows the wrapper +# interface to extend a construction environment for its own purposes +# by subclassing SCons.Environment.Base and then assigning the +# class to SCons.Environment.Environment. + +Environment = Base + + +def NoSubstitutionProxy(subject): + """ + An entry point for returning a proxy subclass instance that overrides + the subst*() methods so they don't actually perform construction + variable substitution. This is specifically intended to be the shim + layer in between global function calls (which don't want construction + variable substitution) and the DefaultEnvironment() (which would + substitute variables if left to its own devices). + + We have to wrap this in a function that allows us to delay definition of + the class until it's necessary, so that when it subclasses Environment + it will pick up whatever Environment subclass the wrapper interface + might have assigned to SCons.Environment.Environment. + """ + class _NoSubstitutionProxy(Environment): + def __init__(self, subject): + self.__dict__['__subject'] = subject + def __getattr__(self, name): + return getattr(self.__dict__['__subject'], name) + def __setattr__(self, name, value): + return setattr(self.__dict__['__subject'], name, value) + def executor_to_lvars(self, kwdict): + if 'executor' in kwdict: + kwdict['lvars'] = kwdict['executor'].get_lvars() + del kwdict['executor'] + else: + kwdict['lvars'] = {} + def raw_to_mode(self, dict): + try: + raw = dict['raw'] + except KeyError: + pass + else: + del dict['raw'] + dict['mode'] = raw + def subst(self, string, *args, **kwargs): + return string + def subst_kw(self, kw, *args, **kwargs): + return kw + def subst_list(self, string, *args, **kwargs): + nargs = (string, self,) + args + nkw = kwargs.copy() + nkw['gvars'] = {} + self.executor_to_lvars(nkw) + self.raw_to_mode(nkw) + return SCons.Subst.scons_subst_list(*nargs, **nkw) + def subst_target_source(self, string, *args, **kwargs): + nargs = (string, self,) + args + nkw = kwargs.copy() + nkw['gvars'] = {} + self.executor_to_lvars(nkw) + self.raw_to_mode(nkw) + return SCons.Subst.scons_subst(*nargs, **nkw) + return _NoSubstitutionProxy(subject) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Errors.py b/tools/scons/scons-local-3.0.5/SCons/Errors.py new file mode 100755 index 0000000000..4f1403db85 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Errors.py @@ -0,0 +1,228 @@ +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +"""SCons.Errors + +This file contains the exception classes used to handle internal +and user errors in SCons. + +""" + +__revision__ = "src/engine/SCons/Errors.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import shutil +import SCons.Util + + +class BuildError(Exception): + """ Errors occurring while building. + + BuildError have the following attributes: + ========================================= + + Information about the cause of the build error: + ----------------------------------------------- + + errstr : a description of the error message + + status : the return code of the action that caused the build error. + Must be set to a non-zero value even if the build error is not due + to an action returning a non-zero returned code. + + exitstatus : SCons exit status due to this build error. + Must be nonzero unless due to an explicit Exit() + call. Not always the same as status, since + actions return a status code that should be + respected, but SCons typically exits with 2 + irrespective of the return value of the failed + action. + + filename : The name of the file or directory that caused the + build error. Set to None if no files are associated with + this error. This might be different from the target + being built. For example, failure to create the + directory in which the target file will appear. It + can be None if the error is not due to a particular + filename. + + exc_info : Info about exception that caused the build + error. Set to (None, None, None) if this build + error is not due to an exception. + + + Information about the cause of the location of the error: + --------------------------------------------------------- + + node : the error occured while building this target node(s) + + executor : the executor that caused the build to fail (might + be None if the build failures is not due to the + executor failing) + + action : the action that caused the build to fail (might be + None if the build failures is not due to the an + action failure) + + command : the command line for the action that caused the + build to fail (might be None if the build failures + is not due to the an action failure) + """ + + def __init__(self, + node=None, errstr="Unknown error", status=2, exitstatus=2, + filename=None, executor=None, action=None, command=None, + exc_info=(None, None, None)): + + # py3: errstr should be string and not bytes. + + self.errstr = SCons.Util.to_String(errstr) + self.status = status + self.exitstatus = exitstatus + self.filename = filename + self.exc_info = exc_info + + self.node = node + self.executor = executor + self.action = action + self.command = command + + Exception.__init__(self, node, errstr, status, exitstatus, filename, + executor, action, command, exc_info) + + def __str__(self): + if self.filename: + return self.filename + ': ' + self.errstr + else: + return self.errstr + +class InternalError(Exception): + pass + +class UserError(Exception): + pass + +class StopError(Exception): + pass + +class EnvironmentError(Exception): + pass + +class MSVCError(IOError): + pass + +class ExplicitExit(Exception): + def __init__(self, node=None, status=None, *args): + self.node = node + self.status = status + self.exitstatus = status + Exception.__init__(self, *args) + +def convert_to_BuildError(status, exc_info=None): + """ + Convert any return code a BuildError Exception. + + :Parameters: + - `status`: can either be a return code or an Exception. + + The buildError.status we set here will normally be + used as the exit status of the "scons" process. + """ + + if not exc_info and isinstance(status, Exception): + exc_info = (status.__class__, status, None) + + + if isinstance(status, BuildError): + buildError = status + buildError.exitstatus = 2 # always exit with 2 on build errors + elif isinstance(status, ExplicitExit): + status = status.status + errstr = 'Explicit exit, status %s' % status + buildError = BuildError( + errstr=errstr, + status=status, # might be 0, OK here + exitstatus=status, # might be 0, OK here + exc_info=exc_info) + elif isinstance(status, (StopError, UserError)): + buildError = BuildError( + errstr=str(status), + status=2, + exitstatus=2, + exc_info=exc_info) + elif isinstance(status, shutil.SameFileError): + # PY3 has a exception for when copying file to itself + # It's object provides info differently than below + try: + filename = status.filename + except AttributeError: + filename = None + + buildError = BuildError( + errstr=status.args[0], + status=status.errno, + exitstatus=2, + filename=filename, + exc_info=exc_info) + + elif isinstance(status, (EnvironmentError, OSError, IOError)): + # If an IOError/OSError happens, raise a BuildError. + # Report the name of the file or directory that caused the + # error, which might be different from the target being built + # (for example, failure to create the directory in which the + # target file will appear). + filename = getattr(status, 'filename', None) + strerror = getattr(status, 'strerror', str(status)) + errno = getattr(status, 'errno', 2) + + buildError = BuildError( + errstr=strerror, + status=errno, + exitstatus=2, + filename=filename, + exc_info=exc_info) + elif isinstance(status, Exception): + buildError = BuildError( + errstr='%s : %s' % (status.__class__.__name__, status), + status=2, + exitstatus=2, + exc_info=exc_info) + elif SCons.Util.is_String(status): + buildError = BuildError( + errstr=status, + status=2, + exitstatus=2) + else: + buildError = BuildError( + errstr="Error %s" % status, + status=status, + exitstatus=2) + + #import sys + #sys.stderr.write("convert_to_BuildError: status %s => (errstr %s, status %s)\n"%(status,buildError.errstr, buildError.status)) + return buildError + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Executor.py b/tools/scons/scons-local-3.0.5/SCons/Executor.py new file mode 100755 index 0000000000..cc3813c65f --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Executor.py @@ -0,0 +1,672 @@ +"""SCons.Executor + +A module for executing actions with specific lists of target and source +Nodes. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from __future__ import print_function + +__revision__ = "src/engine/SCons/Executor.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import collections + +import SCons.Debug +from SCons.Debug import logInstanceCreation +import SCons.Errors +import SCons.Memoize +from SCons.compat import with_metaclass, NoSlotsPyPy + +class Batch(object): + """Remembers exact association between targets + and sources of executor.""" + + __slots__ = ('targets', + 'sources') + + def __init__(self, targets=[], sources=[]): + self.targets = targets + self.sources = sources + + + +class TSList(collections.UserList): + """A class that implements $TARGETS or $SOURCES expansions by wrapping + an executor Method. This class is used in the Executor.lvars() + to delay creation of NodeList objects until they're needed. + + Note that we subclass collections.UserList purely so that the + is_Sequence() function will identify an object of this class as + a list during variable expansion. We're not really using any + collections.UserList methods in practice. + """ + def __init__(self, func): + self.func = func + def __getattr__(self, attr): + nl = self.func() + return getattr(nl, attr) + def __getitem__(self, i): + nl = self.func() + return nl[i] + def __getslice__(self, i, j): + nl = self.func() + i = max(i, 0); j = max(j, 0) + return nl[i:j] + def __str__(self): + nl = self.func() + return str(nl) + def __repr__(self): + nl = self.func() + return repr(nl) + +class TSObject(object): + """A class that implements $TARGET or $SOURCE expansions by wrapping + an Executor method. + """ + def __init__(self, func): + self.func = func + def __getattr__(self, attr): + n = self.func() + return getattr(n, attr) + def __str__(self): + n = self.func() + if n: + return str(n) + return '' + def __repr__(self): + n = self.func() + if n: + return repr(n) + return '' + +def rfile(node): + """ + A function to return the results of a Node's rfile() method, + if it exists, and the Node itself otherwise (if it's a Value + Node, e.g.). + """ + try: + rfile = node.rfile + except AttributeError: + return node + else: + return rfile() + + +def execute_nothing(obj, target, kw): + return 0 + +def execute_action_list(obj, target, kw): + """Actually execute the action list.""" + env = obj.get_build_env() + kw = obj.get_kw(kw) + status = 0 + for act in obj.get_action_list(): + args = ([], [], env) + status = act(*args, **kw) + if isinstance(status, SCons.Errors.BuildError): + status.executor = obj + raise status + elif status: + msg = "Error %s" % status + raise SCons.Errors.BuildError( + errstr=msg, + node=obj.batches[0].targets, + executor=obj, + action=act) + return status + +_do_execute_map = {0 : execute_nothing, + 1 : execute_action_list} + + +def execute_actions_str(obj): + env = obj.get_build_env() + return "\n".join([action.genstring(obj.get_all_targets(), + obj.get_all_sources(), + env) + for action in obj.get_action_list()]) + +def execute_null_str(obj): + return '' + +_execute_str_map = {0 : execute_null_str, + 1 : execute_actions_str} + + +class Executor(object, with_metaclass(NoSlotsPyPy)): + """A class for controlling instances of executing an action. + + This largely exists to hold a single association of an action, + environment, list of environment override dictionaries, targets + and sources for later processing as needed. + """ + + __slots__ = ('pre_actions', + 'post_actions', + 'env', + 'overridelist', + 'batches', + 'builder_kw', + '_memo', + 'lvars', + '_changed_sources_list', + '_changed_targets_list', + '_unchanged_sources_list', + '_unchanged_targets_list', + 'action_list', + '_do_execute', + '_execute_str') + + def __init__(self, action, env=None, overridelist=[{}], + targets=[], sources=[], builder_kw={}): + if SCons.Debug.track_instances: logInstanceCreation(self, 'Executor.Executor') + self.set_action_list(action) + self.pre_actions = [] + self.post_actions = [] + self.env = env + self.overridelist = overridelist + if targets or sources: + self.batches = [Batch(targets[:], sources[:])] + else: + self.batches = [] + self.builder_kw = builder_kw + self._do_execute = 1 + self._execute_str = 1 + self._memo = {} + + def get_lvars(self): + try: + return self.lvars + except AttributeError: + self.lvars = { + 'CHANGED_SOURCES' : TSList(self._get_changed_sources), + 'CHANGED_TARGETS' : TSList(self._get_changed_targets), + 'SOURCE' : TSObject(self._get_source), + 'SOURCES' : TSList(self._get_sources), + 'TARGET' : TSObject(self._get_target), + 'TARGETS' : TSList(self._get_targets), + 'UNCHANGED_SOURCES' : TSList(self._get_unchanged_sources), + 'UNCHANGED_TARGETS' : TSList(self._get_unchanged_targets), + } + return self.lvars + + def _get_changes(self): + cs = [] + ct = [] + us = [] + ut = [] + for b in self.batches: + # don't add targets marked always build to unchanged lists + # add to changed list as they always need to build + if not b.targets[0].always_build and b.targets[0].is_up_to_date(): + us.extend(list(map(rfile, b.sources))) + ut.extend(b.targets) + else: + cs.extend(list(map(rfile, b.sources))) + ct.extend(b.targets) + self._changed_sources_list = SCons.Util.NodeList(cs) + self._changed_targets_list = SCons.Util.NodeList(ct) + self._unchanged_sources_list = SCons.Util.NodeList(us) + self._unchanged_targets_list = SCons.Util.NodeList(ut) + + def _get_changed_sources(self, *args, **kw): + try: + return self._changed_sources_list + except AttributeError: + self._get_changes() + return self._changed_sources_list + + def _get_changed_targets(self, *args, **kw): + try: + return self._changed_targets_list + except AttributeError: + self._get_changes() + return self._changed_targets_list + + def _get_source(self, *args, **kw): + return rfile(self.batches[0].sources[0]).get_subst_proxy() + + def _get_sources(self, *args, **kw): + return SCons.Util.NodeList([rfile(n).get_subst_proxy() for n in self.get_all_sources()]) + + def _get_target(self, *args, **kw): + return self.batches[0].targets[0].get_subst_proxy() + + def _get_targets(self, *args, **kw): + return SCons.Util.NodeList([n.get_subst_proxy() for n in self.get_all_targets()]) + + def _get_unchanged_sources(self, *args, **kw): + try: + return self._unchanged_sources_list + except AttributeError: + self._get_changes() + return self._unchanged_sources_list + + def _get_unchanged_targets(self, *args, **kw): + try: + return self._unchanged_targets_list + except AttributeError: + self._get_changes() + return self._unchanged_targets_list + + def get_action_targets(self): + if not self.action_list: + return [] + targets_string = self.action_list[0].get_targets(self.env, self) + if targets_string[0] == '$': + targets_string = targets_string[1:] + return self.get_lvars()[targets_string] + + def set_action_list(self, action): + import SCons.Util + if not SCons.Util.is_List(action): + if not action: + import SCons.Errors + raise SCons.Errors.UserError("Executor must have an action.") + action = [action] + self.action_list = action + + def get_action_list(self): + if self.action_list is None: + return [] + return self.pre_actions + self.action_list + self.post_actions + + def get_all_targets(self): + """Returns all targets for all batches of this Executor.""" + result = [] + for batch in self.batches: + result.extend(batch.targets) + return result + + def get_all_sources(self): + """Returns all sources for all batches of this Executor.""" + result = [] + for batch in self.batches: + result.extend(batch.sources) + return result + + def get_all_children(self): + """Returns all unique children (dependencies) for all batches + of this Executor. + + The Taskmaster can recognize when it's already evaluated a + Node, so we don't have to make this list unique for its intended + canonical use case, but we expect there to be a lot of redundancy + (long lists of batched .cc files #including the same .h files + over and over), so removing the duplicates once up front should + save the Taskmaster a lot of work. + """ + result = SCons.Util.UniqueList([]) + for target in self.get_all_targets(): + result.extend(target.children()) + return result + + def get_all_prerequisites(self): + """Returns all unique (order-only) prerequisites for all batches + of this Executor. + """ + result = SCons.Util.UniqueList([]) + for target in self.get_all_targets(): + if target.prerequisites is not None: + result.extend(target.prerequisites) + return result + + def get_action_side_effects(self): + + """Returns all side effects for all batches of this + Executor used by the underlying Action. + """ + result = SCons.Util.UniqueList([]) + for target in self.get_action_targets(): + result.extend(target.side_effects) + return result + + @SCons.Memoize.CountMethodCall + def get_build_env(self): + """Fetch or create the appropriate build Environment + for this Executor. + """ + try: + return self._memo['get_build_env'] + except KeyError: + pass + + # Create the build environment instance with appropriate + # overrides. These get evaluated against the current + # environment's construction variables so that users can + # add to existing values by referencing the variable in + # the expansion. + overrides = {} + for odict in self.overridelist: + overrides.update(odict) + + import SCons.Defaults + env = self.env or SCons.Defaults.DefaultEnvironment() + build_env = env.Override(overrides) + + self._memo['get_build_env'] = build_env + + return build_env + + def get_build_scanner_path(self, scanner): + """Fetch the scanner path for this executor's targets and sources. + """ + env = self.get_build_env() + try: + cwd = self.batches[0].targets[0].cwd + except (IndexError, AttributeError): + cwd = None + return scanner.path(env, cwd, + self.get_all_targets(), + self.get_all_sources()) + + def get_kw(self, kw={}): + result = self.builder_kw.copy() + result.update(kw) + result['executor'] = self + return result + + # use extra indirection because with new-style objects (Python 2.2 + # and above) we can't override special methods, and nullify() needs + # to be able to do this. + + def __call__(self, target, **kw): + return _do_execute_map[self._do_execute](self, target, kw) + + def cleanup(self): + self._memo = {} + + def add_sources(self, sources): + """Add source files to this Executor's list. This is necessary + for "multi" Builders that can be called repeatedly to build up + a source file list for a given target.""" + # TODO(batch): extend to multiple batches + assert (len(self.batches) == 1) + # TODO(batch): remove duplicates? + sources = [x for x in sources if x not in self.batches[0].sources] + self.batches[0].sources.extend(sources) + + def get_sources(self): + return self.batches[0].sources + + def add_batch(self, targets, sources): + """Add pair of associated target and source to this Executor's list. + This is necessary for "batch" Builders that can be called repeatedly + to build up a list of matching target and source files that will be + used in order to update multiple target files at once from multiple + corresponding source files, for tools like MSVC that support it.""" + self.batches.append(Batch(targets, sources)) + + def prepare(self): + """ + Preparatory checks for whether this Executor can go ahead + and (try to) build its targets. + """ + for s in self.get_all_sources(): + if s.missing(): + msg = "Source `%s' not found, needed by target `%s'." + raise SCons.Errors.StopError(msg % (s, self.batches[0].targets[0])) + + def add_pre_action(self, action): + self.pre_actions.append(action) + + def add_post_action(self, action): + self.post_actions.append(action) + + # another extra indirection for new-style objects and nullify... + + def __str__(self): + return _execute_str_map[self._execute_str](self) + + def nullify(self): + self.cleanup() + self._do_execute = 0 + self._execute_str = 0 + + @SCons.Memoize.CountMethodCall + def get_contents(self): + """Fetch the signature contents. This is the main reason this + class exists, so we can compute this once and cache it regardless + of how many target or source Nodes there are. + + Returns bytes + """ + try: + return self._memo['get_contents'] + except KeyError: + pass + env = self.get_build_env() + + action_list = self.get_action_list() + all_targets = self.get_all_targets() + all_sources = self.get_all_sources() + + result = bytearray("",'utf-8').join([action.get_contents(all_targets, + all_sources, + env) + for action in action_list]) + + self._memo['get_contents'] = result + return result + + def get_timestamp(self): + """Fetch a time stamp for this Executor. We don't have one, of + course (only files do), but this is the interface used by the + timestamp module. + """ + return 0 + + def scan_targets(self, scanner): + # TODO(batch): scan by batches + self.scan(scanner, self.get_all_targets()) + + def scan_sources(self, scanner): + # TODO(batch): scan by batches + if self.batches[0].sources: + self.scan(scanner, self.get_all_sources()) + + def scan(self, scanner, node_list): + """Scan a list of this Executor's files (targets or sources) for + implicit dependencies and update all of the targets with them. + This essentially short-circuits an N*M scan of the sources for + each individual target, which is a hell of a lot more efficient. + """ + env = self.get_build_env() + path = self.get_build_scanner_path + kw = self.get_kw() + + # TODO(batch): scan by batches) + deps = [] + + for node in node_list: + node.disambiguate() + deps.extend(node.get_implicit_deps(env, scanner, path, kw)) + + deps.extend(self.get_implicit_deps()) + + for tgt in self.get_all_targets(): + tgt.add_to_implicit(deps) + + def _get_unignored_sources_key(self, node, ignore=()): + return (node,) + tuple(ignore) + + @SCons.Memoize.CountDictCall(_get_unignored_sources_key) + def get_unignored_sources(self, node, ignore=()): + key = (node,) + tuple(ignore) + try: + memo_dict = self._memo['get_unignored_sources'] + except KeyError: + memo_dict = {} + self._memo['get_unignored_sources'] = memo_dict + else: + try: + return memo_dict[key] + except KeyError: + pass + + if node: + # TODO: better way to do this (it's a linear search, + # but it may not be critical path)? + sourcelist = [] + for b in self.batches: + if node in b.targets: + sourcelist = b.sources + break + else: + sourcelist = self.get_all_sources() + if ignore: + idict = {} + for i in ignore: + idict[i] = 1 + sourcelist = [s for s in sourcelist if s not in idict] + + memo_dict[key] = sourcelist + + return sourcelist + + def get_implicit_deps(self): + """Return the executor's implicit dependencies, i.e. the nodes of + the commands to be executed.""" + result = [] + build_env = self.get_build_env() + for act in self.get_action_list(): + deps = act.get_implicit_deps(self.get_all_targets(), + self.get_all_sources(), + build_env) + result.extend(deps) + return result + + + +_batch_executors = {} + +def GetBatchExecutor(key): + return _batch_executors[key] + +def AddBatchExecutor(key, executor): + assert key not in _batch_executors + _batch_executors[key] = executor + +nullenv = None + + +import SCons.Util +class NullEnvironment(SCons.Util.Null): + import SCons.CacheDir + _CacheDir_path = None + _CacheDir = SCons.CacheDir.CacheDir(None) + def get_CacheDir(self): + return self._CacheDir + + +def get_NullEnvironment(): + """Use singleton pattern for Null Environments.""" + global nullenv + + if nullenv is None: + nullenv = NullEnvironment() + return nullenv + +class Null(object, with_metaclass(NoSlotsPyPy)): + """A null Executor, with a null build Environment, that does + nothing when the rest of the methods call it. + + This might be able to disappear when we refactor things to + disassociate Builders from Nodes entirely, so we're not + going to worry about unit tests for this--at least for now. + """ + + __slots__ = ('pre_actions', + 'post_actions', + 'env', + 'overridelist', + 'batches', + 'builder_kw', + '_memo', + 'lvars', + '_changed_sources_list', + '_changed_targets_list', + '_unchanged_sources_list', + '_unchanged_targets_list', + 'action_list', + '_do_execute', + '_execute_str') + + def __init__(self, *args, **kw): + if SCons.Debug.track_instances: logInstanceCreation(self, 'Executor.Null') + self.batches = [Batch(kw['targets'][:], [])] + def get_build_env(self): + return get_NullEnvironment() + def get_build_scanner_path(self): + return None + def cleanup(self): + pass + def prepare(self): + pass + def get_unignored_sources(self, *args, **kw): + return tuple(()) + def get_action_targets(self): + return [] + def get_action_list(self): + return [] + def get_all_targets(self): + return self.batches[0].targets + def get_all_sources(self): + return self.batches[0].targets[0].sources + def get_all_children(self): + return self.batches[0].targets[0].children() + def get_all_prerequisites(self): + return [] + def get_action_side_effects(self): + return [] + def __call__(self, *args, **kw): + return 0 + def get_contents(self): + return '' + def _morph(self): + """Morph this Null executor to a real Executor object.""" + batches = self.batches + self.__class__ = Executor + self.__init__([]) + self.batches = batches + + # The following methods require morphing this Null Executor to a + # real Executor object. + + def add_pre_action(self, action): + self._morph() + self.add_pre_action(action) + def add_post_action(self, action): + self._morph() + self.add_post_action(action) + def set_action_list(self, action): + self._morph() + self.set_action_list(action) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Job.py b/tools/scons/scons-local-3.0.5/SCons/Job.py new file mode 100755 index 0000000000..e04914248a --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Job.py @@ -0,0 +1,435 @@ +"""SCons.Job + +This module defines the Serial and Parallel classes that execute tasks to +complete a build. The Jobs class provides a higher level interface to start, +stop, and wait on jobs. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Job.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.compat + +import os +import signal + +import SCons.Errors + +# The default stack size (in kilobytes) of the threads used to execute +# jobs in parallel. +# +# We use a stack size of 256 kilobytes. The default on some platforms +# is too large and prevents us from creating enough threads to fully +# parallelized the build. For example, the default stack size on linux +# is 8 MBytes. + +explicit_stack_size = None +default_stack_size = 256 + +interrupt_msg = 'Build interrupted.' + + +class InterruptState(object): + def __init__(self): + self.interrupted = False + + def set(self): + self.interrupted = True + + def __call__(self): + return self.interrupted + + +class Jobs(object): + """An instance of this class initializes N jobs, and provides + methods for starting, stopping, and waiting on all N jobs. + """ + + def __init__(self, num, taskmaster): + """ + Create 'num' jobs using the given taskmaster. + + If 'num' is 1 or less, then a serial job will be used, + otherwise a parallel job with 'num' worker threads will + be used. + + The 'num_jobs' attribute will be set to the actual number of jobs + allocated. If more than one job is requested but the Parallel + class can't do it, it gets reset to 1. Wrapping interfaces that + care should check the value of 'num_jobs' after initialization. + """ + + self.job = None + if num > 1: + stack_size = explicit_stack_size + if stack_size is None: + stack_size = default_stack_size + + try: + self.job = Parallel(taskmaster, num, stack_size) + self.num_jobs = num + except NameError: + pass + if self.job is None: + self.job = Serial(taskmaster) + self.num_jobs = 1 + + def run(self, postfunc=lambda: None): + """Run the jobs. + + postfunc() will be invoked after the jobs has run. It will be + invoked even if the jobs are interrupted by a keyboard + interrupt (well, in fact by a signal such as either SIGINT, + SIGTERM or SIGHUP). The execution of postfunc() is protected + against keyboard interrupts and is guaranteed to run to + completion.""" + self._setup_sig_handler() + try: + self.job.start() + finally: + postfunc() + self._reset_sig_handler() + + def were_interrupted(self): + """Returns whether the jobs were interrupted by a signal.""" + return self.job.interrupted() + + def _setup_sig_handler(self): + """Setup an interrupt handler so that SCons can shutdown cleanly in + various conditions: + + a) SIGINT: Keyboard interrupt + b) SIGTERM: kill or system shutdown + c) SIGHUP: Controlling shell exiting + + We handle all of these cases by stopping the taskmaster. It + turns out that it's very difficult to stop the build process + by throwing asynchronously an exception such as + KeyboardInterrupt. For example, the python Condition + variables (threading.Condition) and queues do not seem to be + asynchronous-exception-safe. It would require adding a whole + bunch of try/finally block and except KeyboardInterrupt all + over the place. + + Note also that we have to be careful to handle the case when + SCons forks before executing another process. In that case, we + want the child to exit immediately. + """ + def handler(signum, stack, self=self, parentpid=os.getpid()): + if os.getpid() == parentpid: + self.job.taskmaster.stop() + self.job.interrupted.set() + else: + os._exit(2) + + self.old_sigint = signal.signal(signal.SIGINT, handler) + self.old_sigterm = signal.signal(signal.SIGTERM, handler) + try: + self.old_sighup = signal.signal(signal.SIGHUP, handler) + except AttributeError: + pass + + def _reset_sig_handler(self): + """Restore the signal handlers to their previous state (before the + call to _setup_sig_handler().""" + + signal.signal(signal.SIGINT, self.old_sigint) + signal.signal(signal.SIGTERM, self.old_sigterm) + try: + signal.signal(signal.SIGHUP, self.old_sighup) + except AttributeError: + pass + +class Serial(object): + """This class is used to execute tasks in series, and is more efficient + than Parallel, but is only appropriate for non-parallel builds. Only + one instance of this class should be in existence at a time. + + This class is not thread safe. + """ + + def __init__(self, taskmaster): + """Create a new serial job given a taskmaster. + + The taskmaster's next_task() method should return the next task + that needs to be executed, or None if there are no more tasks. The + taskmaster's executed() method will be called for each task when it + is successfully executed, or failed() will be called if it failed to + execute (e.g. execute() raised an exception).""" + + self.taskmaster = taskmaster + self.interrupted = InterruptState() + + def start(self): + """Start the job. This will begin pulling tasks from the taskmaster + and executing them, and return when there are no more tasks. If a task + fails to execute (i.e. execute() raises an exception), then the job will + stop.""" + + while True: + task = self.taskmaster.next_task() + + if task is None: + break + + try: + task.prepare() + if task.needs_execute(): + task.execute() + except Exception as e: + if self.interrupted(): + try: + raise SCons.Errors.BuildError( + task.targets[0], errstr=interrupt_msg) + except: + task.exception_set() + else: + task.exception_set() + + # Let the failed() callback function arrange for the + # build to stop if that's appropriate. + task.failed() + else: + task.executed() + + task.postprocess() + self.taskmaster.cleanup() + + +# Trap import failure so that everything in the Job module but the +# Parallel class (and its dependent classes) will work if the interpreter +# doesn't support threads. +try: + import queue + import threading +except ImportError: + pass +else: + class Worker(threading.Thread): + """A worker thread waits on a task to be posted to its request queue, + dequeues the task, executes it, and posts a tuple including the task + and a boolean indicating whether the task executed successfully. """ + + def __init__(self, requestQueue, resultsQueue, interrupted): + threading.Thread.__init__(self) + self.setDaemon(1) + self.requestQueue = requestQueue + self.resultsQueue = resultsQueue + self.interrupted = interrupted + self.start() + + def run(self): + while True: + task = self.requestQueue.get() + + if task is None: + # The "None" value is used as a sentinel by + # ThreadPool.cleanup(). This indicates that there + # are no more tasks, so we should quit. + break + + try: + if self.interrupted(): + raise SCons.Errors.BuildError( + task.targets[0], errstr=interrupt_msg) + task.execute() + except: + task.exception_set() + ok = False + else: + ok = True + + self.resultsQueue.put((task, ok)) + + class ThreadPool(object): + """This class is responsible for spawning and managing worker threads.""" + + def __init__(self, num, stack_size, interrupted): + """Create the request and reply queues, and 'num' worker threads. + + One must specify the stack size of the worker threads. The + stack size is specified in kilobytes. + """ + self.requestQueue = queue.Queue(0) + self.resultsQueue = queue.Queue(0) + + try: + prev_size = threading.stack_size(stack_size*1024) + except AttributeError as e: + # Only print a warning if the stack size has been + # explicitly set. + if not explicit_stack_size is None: + msg = "Setting stack size is unsupported by this version of Python:\n " + \ + e.args[0] + SCons.Warnings.warn(SCons.Warnings.StackSizeWarning, msg) + except ValueError as e: + msg = "Setting stack size failed:\n " + str(e) + SCons.Warnings.warn(SCons.Warnings.StackSizeWarning, msg) + + # Create worker threads + self.workers = [] + for _ in range(num): + worker = Worker(self.requestQueue, self.resultsQueue, interrupted) + self.workers.append(worker) + + if 'prev_size' in locals(): + threading.stack_size(prev_size) + + def put(self, task): + """Put task into request queue.""" + self.requestQueue.put(task) + + def get(self): + """Remove and return a result tuple from the results queue.""" + return self.resultsQueue.get() + + def preparation_failed(self, task): + self.resultsQueue.put((task, False)) + + def cleanup(self): + """ + Shuts down the thread pool, giving each worker thread a + chance to shut down gracefully. + """ + # For each worker thread, put a sentinel "None" value + # on the requestQueue (indicating that there's no work + # to be done) so that each worker thread will get one and + # terminate gracefully. + for _ in self.workers: + self.requestQueue.put(None) + + # Wait for all of the workers to terminate. + # + # If we don't do this, later Python versions (2.4, 2.5) often + # seem to raise exceptions during shutdown. This happens + # in requestQueue.get(), as an assertion failure that + # requestQueue.not_full is notified while not acquired, + # seemingly because the main thread has shut down (or is + # in the process of doing so) while the workers are still + # trying to pull sentinels off the requestQueue. + # + # Normally these terminations should happen fairly quickly, + # but we'll stick a one-second timeout on here just in case + # someone gets hung. + for worker in self.workers: + worker.join(1.0) + self.workers = [] + + class Parallel(object): + """This class is used to execute tasks in parallel, and is somewhat + less efficient than Serial, but is appropriate for parallel builds. + + This class is thread safe. + """ + + def __init__(self, taskmaster, num, stack_size): + """Create a new parallel job given a taskmaster. + + The taskmaster's next_task() method should return the next + task that needs to be executed, or None if there are no more + tasks. The taskmaster's executed() method will be called + for each task when it is successfully executed, or failed() + will be called if the task failed to execute (i.e. execute() + raised an exception). + + Note: calls to taskmaster are serialized, but calls to + execute() on distinct tasks are not serialized, because + that is the whole point of parallel jobs: they can execute + multiple tasks simultaneously. """ + + self.taskmaster = taskmaster + self.interrupted = InterruptState() + self.tp = ThreadPool(num, stack_size, self.interrupted) + + self.maxjobs = num + + def start(self): + """Start the job. This will begin pulling tasks from the + taskmaster and executing them, and return when there are no + more tasks. If a task fails to execute (i.e. execute() raises + an exception), then the job will stop.""" + + jobs = 0 + + while True: + # Start up as many available tasks as we're + # allowed to. + while jobs < self.maxjobs: + task = self.taskmaster.next_task() + if task is None: + break + + try: + # prepare task for execution + task.prepare() + except: + task.exception_set() + task.failed() + task.postprocess() + else: + if task.needs_execute(): + # dispatch task + self.tp.put(task) + jobs = jobs + 1 + else: + task.executed() + task.postprocess() + + if not task and not jobs: break + + # Let any/all completed tasks finish up before we go + # back and put the next batch of tasks on the queue. + while True: + task, ok = self.tp.get() + jobs = jobs - 1 + + if ok: + task.executed() + else: + if self.interrupted(): + try: + raise SCons.Errors.BuildError( + task.targets[0], errstr=interrupt_msg) + except: + task.exception_set() + + # Let the failed() callback function arrange + # for the build to stop if that's appropriate. + task.failed() + + task.postprocess() + + if self.tp.resultsQueue.empty(): + break + + self.tp.cleanup() + self.taskmaster.cleanup() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Memoize.py b/tools/scons/scons-local-3.0.5/SCons/Memoize.py new file mode 100755 index 0000000000..12fe043502 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Memoize.py @@ -0,0 +1,245 @@ +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +from __future__ import print_function + +__revision__ = "src/engine/SCons/Memoize.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +__doc__ = """Memoizer + +A decorator-based implementation to count hits and misses of the computed +values that various methods cache in memory. + +Use of this modules assumes that wrapped methods be coded to cache their +values in a consistent way. In particular, it requires that the class uses a +dictionary named "_memo" to store the cached values. + +Here is an example of wrapping a method that returns a computed value, +with no input parameters:: + + @SCons.Memoize.CountMethodCall + def foo(self): + + try: # Memoization + return self._memo['foo'] # Memoization + except KeyError: # Memoization + pass # Memoization + + result = self.compute_foo_value() + + self._memo['foo'] = result # Memoization + + return result + +Here is an example of wrapping a method that will return different values +based on one or more input arguments:: + + def _bar_key(self, argument): # Memoization + return argument # Memoization + + @SCons.Memoize.CountDictCall(_bar_key) + def bar(self, argument): + + memo_key = argument # Memoization + try: # Memoization + memo_dict = self._memo['bar'] # Memoization + except KeyError: # Memoization + memo_dict = {} # Memoization + self._memo['dict'] = memo_dict # Memoization + else: # Memoization + try: # Memoization + return memo_dict[memo_key] # Memoization + except KeyError: # Memoization + pass # Memoization + + result = self.compute_bar_value(argument) + + memo_dict[memo_key] = result # Memoization + + return result + +Deciding what to cache is tricky, because different configurations +can have radically different performance tradeoffs, and because the +tradeoffs involved are often so non-obvious. Consequently, deciding +whether or not to cache a given method will likely be more of an art than +a science, but should still be based on available data from this module. +Here are some VERY GENERAL guidelines about deciding whether or not to +cache return values from a method that's being called a lot: + + -- The first question to ask is, "Can we change the calling code + so this method isn't called so often?" Sometimes this can be + done by changing the algorithm. Sometimes the *caller* should + be memoized, not the method you're looking at. + + -- The memoized function should be timed with multiple configurations + to make sure it doesn't inadvertently slow down some other + configuration. + + -- When memoizing values based on a dictionary key composed of + input arguments, you don't need to use all of the arguments + if some of them don't affect the return values. + +""" + +# A flag controlling whether or not we actually use memoization. +use_memoizer = None + +# Global list of counter objects +CounterList = {} + +class Counter(object): + """ + Base class for counting memoization hits and misses. + + We expect that the initialization in a matching decorator will + fill in the correct class name and method name that represents + the name of the function being counted. + """ + def __init__(self, cls_name, method_name): + """ + """ + self.cls_name = cls_name + self.method_name = method_name + self.hit = 0 + self.miss = 0 + def key(self): + return self.cls_name+'.'+self.method_name + def display(self): + print(" {:7d} hits {:7d} misses {}()".format(self.hit, self.miss, self.key())) + def __eq__(self, other): + try: + return self.key() == other.key() + except AttributeError: + return True + +class CountValue(Counter): + """ + A counter class for simple, atomic memoized values. + + A CountValue object should be instantiated in a decorator for each of + the class's methods that memoizes its return value by simply storing + the return value in its _memo dictionary. + """ + def count(self, *args, **kw): + """ Counts whether the memoized value has already been + set (a hit) or not (a miss). + """ + obj = args[0] + if self.method_name in obj._memo: + self.hit = self.hit + 1 + else: + self.miss = self.miss + 1 + +class CountDict(Counter): + """ + A counter class for memoized values stored in a dictionary, with + keys based on the method's input arguments. + + A CountDict object is instantiated in a decorator for each of the + class's methods that memoizes its return value in a dictionary, + indexed by some key that can be computed from one or more of + its input arguments. + """ + def __init__(self, cls_name, method_name, keymaker): + """ + """ + Counter.__init__(self, cls_name, method_name) + self.keymaker = keymaker + def count(self, *args, **kw): + """ Counts whether the computed key value is already present + in the memoization dictionary (a hit) or not (a miss). + """ + obj = args[0] + try: + memo_dict = obj._memo[self.method_name] + except KeyError: + self.miss = self.miss + 1 + else: + key = self.keymaker(*args, **kw) + if key in memo_dict: + self.hit = self.hit + 1 + else: + self.miss = self.miss + 1 + +def Dump(title=None): + """ Dump the hit/miss count for all the counters + collected so far. + """ + if title: + print(title) + for counter in sorted(CounterList): + CounterList[counter].display() + +def EnableMemoization(): + global use_memoizer + use_memoizer = 1 + +def CountMethodCall(fn): + """ Decorator for counting memoizer hits/misses while retrieving + a simple value in a class method. It wraps the given method + fn and uses a CountValue object to keep track of the + caching statistics. + Wrapping gets enabled by calling EnableMemoization(). + """ + if use_memoizer: + def wrapper(self, *args, **kwargs): + global CounterList + key = self.__class__.__name__+'.'+fn.__name__ + if key not in CounterList: + CounterList[key] = CountValue(self.__class__.__name__, fn.__name__) + CounterList[key].count(self, *args, **kwargs) + return fn(self, *args, **kwargs) + wrapper.__name__= fn.__name__ + return wrapper + else: + return fn + +def CountDictCall(keyfunc): + """ Decorator for counting memoizer hits/misses while accessing + dictionary values with a key-generating function. Like + CountMethodCall above, it wraps the given method + fn and uses a CountDict object to keep track of the + caching statistics. The dict-key function keyfunc has to + get passed in the decorator call and gets stored in the + CountDict instance. + Wrapping gets enabled by calling EnableMemoization(). + """ + def decorator(fn): + if use_memoizer: + def wrapper(self, *args, **kwargs): + global CounterList + key = self.__class__.__name__+'.'+fn.__name__ + if key not in CounterList: + CounterList[key] = CountDict(self.__class__.__name__, fn.__name__, keyfunc) + CounterList[key].count(self, *args, **kwargs) + return fn(self, *args, **kwargs) + wrapper.__name__= fn.__name__ + return wrapper + else: + return fn + return decorator + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Node/Alias.py b/tools/scons/scons-local-3.0.5/SCons/Node/Alias.py new file mode 100755 index 0000000000..8fbeef7534 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Node/Alias.py @@ -0,0 +1,181 @@ + +"""scons.Node.Alias + +Alias nodes. + +This creates a hash of global Aliases (dummy targets). + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Node/Alias.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import collections + +import SCons.Errors +import SCons.Node +import SCons.Util + +class AliasNameSpace(collections.UserDict): + def Alias(self, name, **kw): + if isinstance(name, SCons.Node.Alias.Alias): + return name + try: + a = self[name] + except KeyError: + a = SCons.Node.Alias.Alias(name, **kw) + self[name] = a + return a + + def lookup(self, name, **kw): + try: + return self[name] + except KeyError: + return None + +class AliasNodeInfo(SCons.Node.NodeInfoBase): + __slots__ = ('csig',) + current_version_id = 2 + field_list = ['csig'] + def str_to_node(self, s): + return default_ans.Alias(s) + + def __getstate__(self): + """ + Return all fields that shall be pickled. Walk the slots in the class + hierarchy and add those to the state dictionary. If a '__dict__' slot is + available, copy all entries to the dictionary. Also include the version + id, which is fixed for all instances of a class. + """ + state = getattr(self, '__dict__', {}).copy() + for obj in type(self).mro(): + for name in getattr(obj,'__slots__',()): + if hasattr(self, name): + state[name] = getattr(self, name) + + state['_version_id'] = self.current_version_id + try: + del state['__weakref__'] + except KeyError: + pass + + return state + + def __setstate__(self, state): + """ + Restore the attributes from a pickled state. + """ + # TODO check or discard version + del state['_version_id'] + for key, value in state.items(): + if key not in ('__weakref__',): + setattr(self, key, value) + + +class AliasBuildInfo(SCons.Node.BuildInfoBase): + __slots__ = () + current_version_id = 2 + +class Alias(SCons.Node.Node): + + NodeInfo = AliasNodeInfo + BuildInfo = AliasBuildInfo + + def __init__(self, name): + SCons.Node.Node.__init__(self) + self.name = name + self.changed_since_last_build = 1 + self.store_info = 0 + + def str_for_display(self): + return '"' + self.__str__() + '"' + + def __str__(self): + return self.name + + def make_ready(self): + self.get_csig() + + really_build = SCons.Node.Node.build + is_up_to_date = SCons.Node.Node.children_are_up_to_date + + def is_under(self, dir): + # Make Alias nodes get built regardless of + # what directory scons was run from. Alias nodes + # are outside the filesystem: + return 1 + + def get_contents(self): + """The contents of an alias is the concatenation + of the content signatures of all its sources.""" + childsigs = [n.get_csig() for n in self.children()] + return ''.join(childsigs) + + def sconsign(self): + """An Alias is not recorded in .sconsign files""" + pass + + # + # + # + + def build(self): + """A "builder" for aliases.""" + pass + + def convert(self): + try: del self.builder + except AttributeError: pass + self.reset_executor() + self.build = self.really_build + + def get_csig(self): + """ + Generate a node's content signature, the digested signature + of its content. + + node - the node + cache - alternate node to use for the signature cache + returns - the content signature + """ + try: + return self.ninfo.csig + except AttributeError: + pass + + contents = self.get_contents() + csig = SCons.Util.MD5signature(contents) + self.get_ninfo().csig = csig + return csig + +default_ans = AliasNameSpace() + +SCons.Node.arg2nodes_lookups.append(default_ans.lookup) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Node/FS.py b/tools/scons/scons-local-3.0.5/SCons/Node/FS.py new file mode 100755 index 0000000000..be9f7fdf96 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Node/FS.py @@ -0,0 +1,3782 @@ +"""scons.Node.FS + +File system nodes. + +These Nodes represent the canonical external objects that people think +of when they think of building software: files and directories. + +This holds a "default_fs" variable that should be initialized with an FS +that can be used by scripts or modules looking for the canonical default. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from __future__ import print_function + +__revision__ = "src/engine/SCons/Node/FS.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import fnmatch +import os +import re +import shutil +import stat +import sys +import time +import codecs +from itertools import chain + +import SCons.Action +import SCons.Debug +from SCons.Debug import logInstanceCreation +import SCons.Errors +import SCons.Memoize +import SCons.Node +import SCons.Node.Alias +import SCons.Subst +import SCons.Util +import SCons.Warnings + +from SCons.Debug import Trace +from . import DeciderNeedsNode + +print_duplicate = 0 + +MD5_TIMESTAMP_DEBUG = False + + +def sconsign_none(node): + raise NotImplementedError + +def sconsign_dir(node): + """Return the .sconsign file info for this directory, + creating it first if necessary.""" + if not node._sconsign: + import SCons.SConsign + node._sconsign = SCons.SConsign.ForDirectory(node) + return node._sconsign + +_sconsign_map = {0 : sconsign_none, + 1 : sconsign_dir} + +class FileBuildInfoFileToCsigMappingError(Exception): + pass + +class EntryProxyAttributeError(AttributeError): + """ + An AttributeError subclass for recording and displaying the name + of the underlying Entry involved in an AttributeError exception. + """ + def __init__(self, entry_proxy, attribute): + AttributeError.__init__(self) + self.entry_proxy = entry_proxy + self.attribute = attribute + def __str__(self): + entry = self.entry_proxy.get() + fmt = "%s instance %s has no attribute %s" + return fmt % (entry.__class__.__name__, + repr(entry.name), + repr(self.attribute)) + +# The max_drift value: by default, use a cached signature value for +# any file that's been untouched for more than two days. +default_max_drift = 2*24*60*60 + +# +# We stringify these file system Nodes a lot. Turning a file system Node +# into a string is non-trivial, because the final string representation +# can depend on a lot of factors: whether it's a derived target or not, +# whether it's linked to a repository or source directory, and whether +# there's duplication going on. The normal technique for optimizing +# calculations like this is to memoize (cache) the string value, so you +# only have to do the calculation once. +# +# A number of the above factors, however, can be set after we've already +# been asked to return a string for a Node, because a Repository() or +# VariantDir() call or the like may not occur until later in SConscript +# files. So this variable controls whether we bother trying to save +# string values for Nodes. The wrapper interface can set this whenever +# they're done mucking with Repository and VariantDir and the other stuff, +# to let this module know it can start returning saved string values +# for Nodes. +# +Save_Strings = None + +def save_strings(val): + global Save_Strings + Save_Strings = val + +# +# Avoid unnecessary function calls by recording a Boolean value that +# tells us whether or not os.path.splitdrive() actually does anything +# on this system, and therefore whether we need to bother calling it +# when looking up path names in various methods below. +# + +do_splitdrive = None +_my_splitdrive =None + +def initialize_do_splitdrive(): + global do_splitdrive + global has_unc + drive, path = os.path.splitdrive('X:/foo') + # splitunc is removed from python 3.7 and newer + # so we can also just test if splitdrive works with UNC + has_unc = (hasattr(os.path, 'splitunc') + or os.path.splitdrive(r'\\split\drive\test')[0] == r'\\split\drive') + + do_splitdrive = not not drive or has_unc + + global _my_splitdrive + if has_unc: + def splitdrive(p): + if p[1:2] == ':': + return p[:2], p[2:] + if p[0:2] == '//': + # Note that we leave a leading slash in the path + # because UNC paths are always absolute. + return '//', p[1:] + return '', p + else: + def splitdrive(p): + if p[1:2] == ':': + return p[:2], p[2:] + return '', p + _my_splitdrive = splitdrive + + # Keep some commonly used values in global variables to skip to + # module look-up costs. + global OS_SEP + global UNC_PREFIX + global os_sep_is_slash + + OS_SEP = os.sep + UNC_PREFIX = OS_SEP + OS_SEP + os_sep_is_slash = OS_SEP == '/' + +initialize_do_splitdrive() + +# Used to avoid invoking os.path.normpath if not necessary. +needs_normpath_check = re.compile( + r''' + # We need to renormalize the path if it contains any consecutive + # '/' characters. + .*// | + + # We need to renormalize the path if it contains a '..' directory. + # Note that we check for all the following cases: + # + # a) The path is a single '..' + # b) The path starts with '..'. E.g. '../' or '../moredirs' + # but we not match '..abc/'. + # c) The path ends with '..'. E.g. '/..' or 'dirs/..' + # d) The path contains a '..' in the middle. + # E.g. dirs/../moredirs + + (.*/)?\.\.(?:/|$) | + + # We need to renormalize the path if it contains a '.' + # directory, but NOT if it is a single '.' '/' characters. We + # do not want to match a single '.' because this case is checked + # for explicitly since this is common enough case. + # + # Note that we check for all the following cases: + # + # a) We don't match a single '.' + # b) We match if the path starts with '.'. E.g. './' or + # './moredirs' but we not match '.abc/'. + # c) We match if the path ends with '.'. E.g. '/.' or + # 'dirs/.' + # d) We match if the path contains a '.' in the middle. + # E.g. dirs/./moredirs + + \./|.*/\.(?:/|$) + + ''', + re.VERBOSE + ) +needs_normpath_match = needs_normpath_check.match + +# +# SCons.Action objects for interacting with the outside world. +# +# The Node.FS methods in this module should use these actions to +# create and/or remove files and directories; they should *not* use +# os.{link,symlink,unlink,mkdir}(), etc., directly. +# +# Using these SCons.Action objects ensures that descriptions of these +# external activities are properly displayed, that the displays are +# suppressed when the -s (silent) option is used, and (most importantly) +# the actions are disabled when the the -n option is used, in which case +# there should be *no* changes to the external file system(s)... +# + +# For Now disable hard & softlinks for win32 +# PY3 supports them, but the rest of SCons is not ready for this +# in some cases user permissions may be required. +# TODO: See if theres a reasonable way to enable using links on win32/64 + +if hasattr(os, 'link') and sys.platform != 'win32': + def _hardlink_func(fs, src, dst): + # If the source is a symlink, we can't just hard-link to it + # because a relative symlink may point somewhere completely + # different. We must disambiguate the symlink and then + # hard-link the final destination file. + while fs.islink(src): + link = fs.readlink(src) + if not os.path.isabs(link): + src = link + else: + src = os.path.join(os.path.dirname(src), link) + fs.link(src, dst) +else: + _hardlink_func = None + +if hasattr(os, 'symlink') and sys.platform != 'win32': + def _softlink_func(fs, src, dst): + fs.symlink(src, dst) +else: + _softlink_func = None + +def _copy_func(fs, src, dest): + shutil.copy2(src, dest) + st = fs.stat(src) + fs.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE) + + +Valid_Duplicates = ['hard-soft-copy', 'soft-hard-copy', + 'hard-copy', 'soft-copy', 'copy'] + +Link_Funcs = [] # contains the callables of the specified duplication style + +def set_duplicate(duplicate): + # Fill in the Link_Funcs list according to the argument + # (discarding those not available on the platform). + + # Set up the dictionary that maps the argument names to the + # underlying implementations. We do this inside this function, + # not in the top-level module code, so that we can remap os.link + # and os.symlink for testing purposes. + link_dict = { + 'hard' : _hardlink_func, + 'soft' : _softlink_func, + 'copy' : _copy_func + } + + if not duplicate in Valid_Duplicates: + raise SCons.Errors.InternalError("The argument of set_duplicate " + "should be in Valid_Duplicates") + global Link_Funcs + Link_Funcs = [] + for func in duplicate.split('-'): + if link_dict[func]: + Link_Funcs.append(link_dict[func]) + +def LinkFunc(target, source, env): + """ + Relative paths cause problems with symbolic links, so + we use absolute paths, which may be a problem for people + who want to move their soft-linked src-trees around. Those + people should use the 'hard-copy' mode, softlinks cannot be + used for that; at least I have no idea how ... + """ + src = source[0].get_abspath() + dest = target[0].get_abspath() + dir, file = os.path.split(dest) + if dir and not target[0].fs.isdir(dir): + os.makedirs(dir) + if not Link_Funcs: + # Set a default order of link functions. + set_duplicate('hard-soft-copy') + fs = source[0].fs + # Now link the files with the previously specified order. + for func in Link_Funcs: + try: + func(fs, src, dest) + break + except (IOError, OSError): + # An OSError indicates something happened like a permissions + # problem or an attempt to symlink across file-system + # boundaries. An IOError indicates something like the file + # not existing. In either case, keeping trying additional + # functions in the list and only raise an error if the last + # one failed. + if func == Link_Funcs[-1]: + # exception of the last link method (copy) are fatal + raise + return 0 + +Link = SCons.Action.Action(LinkFunc, None) +def LocalString(target, source, env): + return 'Local copy of %s from %s' % (target[0], source[0]) + +LocalCopy = SCons.Action.Action(LinkFunc, LocalString) + +def UnlinkFunc(target, source, env): + t = target[0] + t.fs.unlink(t.get_abspath()) + return 0 + +Unlink = SCons.Action.Action(UnlinkFunc, None) + +def MkdirFunc(target, source, env): + t = target[0] + # This os.path.exists test looks redundant, but it's possible + # when using Install() to install multiple dirs outside the + # source tree to get a case where t.exists() is true but + # the path does already exist, so this prevents spurious + # build failures in that case. See test/Install/multi-dir. + if not t.exists() and not os.path.exists(t.get_abspath()): + t.fs.mkdir(t.get_abspath()) + return 0 + +Mkdir = SCons.Action.Action(MkdirFunc, None, presub=None) + +MkdirBuilder = None + +def get_MkdirBuilder(): + global MkdirBuilder + if MkdirBuilder is None: + import SCons.Builder + import SCons.Defaults + # "env" will get filled in by Executor.get_build_env() + # calling SCons.Defaults.DefaultEnvironment() when necessary. + MkdirBuilder = SCons.Builder.Builder(action = Mkdir, + env = None, + explain = None, + is_explicit = None, + target_scanner = SCons.Defaults.DirEntryScanner, + name = "MkdirBuilder") + return MkdirBuilder + +class _Null(object): + pass + +_null = _Null() + +# Cygwin's os.path.normcase pretends it's on a case-sensitive filesystem. +_is_cygwin = sys.platform == "cygwin" +if os.path.normcase("TeSt") == os.path.normpath("TeSt") and not _is_cygwin: + def _my_normcase(x): + return x +else: + def _my_normcase(x): + return x.upper() + + + +class DiskChecker(object): + def __init__(self, type, do, ignore): + self.type = type + self.do = do + self.ignore = ignore + self.func = do + def __call__(self, *args, **kw): + return self.func(*args, **kw) + def set(self, list): + if self.type in list: + self.func = self.do + else: + self.func = self.ignore + +def do_diskcheck_match(node, predicate, errorfmt): + result = predicate() + try: + # If calling the predicate() cached a None value from stat(), + # remove it so it doesn't interfere with later attempts to + # build this Node as we walk the DAG. (This isn't a great way + # to do this, we're reaching into an interface that doesn't + # really belong to us, but it's all about performance, so + # for now we'll just document the dependency...) + if node._memo['stat'] is None: + del node._memo['stat'] + except (AttributeError, KeyError): + pass + if result: + raise TypeError(errorfmt % node.get_abspath()) + +def ignore_diskcheck_match(node, predicate, errorfmt): + pass + + + +diskcheck_match = DiskChecker('match', do_diskcheck_match, ignore_diskcheck_match) + +diskcheckers = [ + diskcheck_match, +] + +def set_diskcheck(list): + for dc in diskcheckers: + dc.set(list) + +def diskcheck_types(): + return [dc.type for dc in diskcheckers] + + + +class EntryProxy(SCons.Util.Proxy): + + __str__ = SCons.Util.Delegate('__str__') + + # In PY3 if a class defines __eq__, then it must explicitly provide + # __hash__. Since SCons.Util.Proxy provides __eq__ we need the following + # see: https://docs.python.org/3.1/reference/datamodel.html#object.__hash__ + __hash__ = SCons.Util.Delegate('__hash__') + + def __get_abspath(self): + entry = self.get() + return SCons.Subst.SpecialAttrWrapper(entry.get_abspath(), + entry.name + "_abspath") + + def __get_filebase(self): + name = self.get().name + return SCons.Subst.SpecialAttrWrapper(SCons.Util.splitext(name)[0], + name + "_filebase") + + def __get_suffix(self): + name = self.get().name + return SCons.Subst.SpecialAttrWrapper(SCons.Util.splitext(name)[1], + name + "_suffix") + + def __get_file(self): + name = self.get().name + return SCons.Subst.SpecialAttrWrapper(name, name + "_file") + + def __get_base_path(self): + """Return the file's directory and file name, with the + suffix stripped.""" + entry = self.get() + return SCons.Subst.SpecialAttrWrapper(SCons.Util.splitext(entry.get_path())[0], + entry.name + "_base") + + def __get_posix_path(self): + """Return the path with / as the path separator, + regardless of platform.""" + if os_sep_is_slash: + return self + else: + entry = self.get() + r = entry.get_path().replace(OS_SEP, '/') + return SCons.Subst.SpecialAttrWrapper(r, entry.name + "_posix") + + def __get_windows_path(self): + """Return the path with \ as the path separator, + regardless of platform.""" + if OS_SEP == '\\': + return self + else: + entry = self.get() + r = entry.get_path().replace(OS_SEP, '\\') + return SCons.Subst.SpecialAttrWrapper(r, entry.name + "_windows") + + def __get_srcnode(self): + return EntryProxy(self.get().srcnode()) + + def __get_srcdir(self): + """Returns the directory containing the source node linked to this + node via VariantDir(), or the directory of this node if not linked.""" + return EntryProxy(self.get().srcnode().dir) + + def __get_rsrcnode(self): + return EntryProxy(self.get().srcnode().rfile()) + + def __get_rsrcdir(self): + """Returns the directory containing the source node linked to this + node via VariantDir(), or the directory of this node if not linked.""" + return EntryProxy(self.get().srcnode().rfile().dir) + + def __get_dir(self): + return EntryProxy(self.get().dir) + + dictSpecialAttrs = { "base" : __get_base_path, + "posix" : __get_posix_path, + "windows" : __get_windows_path, + "win32" : __get_windows_path, + "srcpath" : __get_srcnode, + "srcdir" : __get_srcdir, + "dir" : __get_dir, + "abspath" : __get_abspath, + "filebase" : __get_filebase, + "suffix" : __get_suffix, + "file" : __get_file, + "rsrcpath" : __get_rsrcnode, + "rsrcdir" : __get_rsrcdir, + } + + def __getattr__(self, name): + # This is how we implement the "special" attributes + # such as base, posix, srcdir, etc. + try: + attr_function = self.dictSpecialAttrs[name] + except KeyError: + try: + attr = SCons.Util.Proxy.__getattr__(self, name) + except AttributeError as e: + # Raise our own AttributeError subclass with an + # overridden __str__() method that identifies the + # name of the entry that caused the exception. + raise EntryProxyAttributeError(self, name) + return attr + else: + return attr_function(self) + + +class Base(SCons.Node.Node): + """A generic class for file system entries. This class is for + when we don't know yet whether the entry being looked up is a file + or a directory. Instances of this class can morph into either + Dir or File objects by a later, more precise lookup. + + Note: this class does not define __cmp__ and __hash__ for + efficiency reasons. SCons does a lot of comparing of + Node.FS.{Base,Entry,File,Dir} objects, so those operations must be + as fast as possible, which means we want to use Python's built-in + object identity comparisons. + """ + + __slots__ = ['name', + 'fs', + '_abspath', + '_labspath', + '_path', + '_tpath', + '_path_elements', + 'dir', + 'cwd', + 'duplicate', + '_local', + 'sbuilder', + '_proxy', + '_func_sconsign'] + + def __init__(self, name, directory, fs): + """Initialize a generic Node.FS.Base object. + + Call the superclass initialization, take care of setting up + our relative and absolute paths, identify our parent + directory, and indicate that this node should use + signatures.""" + + if SCons.Debug.track_instances: logInstanceCreation(self, 'Node.FS.Base') + SCons.Node.Node.__init__(self) + + # Filenames and paths are probably reused and are intern'ed to save some memory. + # Filename with extension as it was specified when the object was + # created; to obtain filesystem path, use Python str() function + self.name = SCons.Util.silent_intern(name) + self.fs = fs #: Reference to parent Node.FS object + + assert directory, "A directory must be provided" + + self._abspath = None + self._labspath = None + self._path = None + self._tpath = None + self._path_elements = None + + self.dir = directory + self.cwd = None # will hold the SConscript directory for target nodes + self.duplicate = directory.duplicate + self.changed_since_last_build = 2 + self._func_sconsign = 0 + self._func_exists = 2 + self._func_rexists = 2 + self._func_get_contents = 0 + self._func_target_from_source = 1 + self.store_info = 1 + + def str_for_display(self): + return '"' + self.__str__() + '"' + + def must_be_same(self, klass): + """ + This node, which already existed, is being looked up as the + specified klass. Raise an exception if it isn't. + """ + if isinstance(self, klass) or klass is Entry: + return + raise TypeError("Tried to lookup %s '%s' as a %s." %\ + (self.__class__.__name__, self.get_internal_path(), klass.__name__)) + + def get_dir(self): + return self.dir + + def get_suffix(self): + return SCons.Util.splitext(self.name)[1] + + def rfile(self): + return self + + def __getattr__(self, attr): + """ Together with the node_bwcomp dict defined below, + this method provides a simple backward compatibility + layer for the Node attributes 'abspath', 'labspath', + 'path', 'tpath', 'suffix' and 'path_elements'. These Node + attributes used to be directly available in v2.3 and earlier, but + have been replaced by getter methods that initialize the + single variables lazily when required, in order to save memory. + The redirection to the getters lets older Tools and + SConstruct continue to work without any additional changes, + fully transparent to the user. + Note, that __getattr__ is only called as fallback when the + requested attribute can't be found, so there should be no + speed performance penalty involved for standard builds. + """ + if attr in node_bwcomp: + return node_bwcomp[attr](self) + + raise AttributeError("%r object has no attribute %r" % + (self.__class__, attr)) + + def __str__(self): + """A Node.FS.Base object's string representation is its path + name.""" + global Save_Strings + if Save_Strings: + return self._save_str() + return self._get_str() + + def __lt__(self, other): + """ less than operator used by sorting on py3""" + return str(self) < str(other) + + @SCons.Memoize.CountMethodCall + def _save_str(self): + try: + return self._memo['_save_str'] + except KeyError: + pass + result = SCons.Util.silent_intern(self._get_str()) + self._memo['_save_str'] = result + return result + + def _get_str(self): + global Save_Strings + if self.duplicate or self.is_derived(): + return self.get_path() + srcnode = self.srcnode() + if srcnode.stat() is None and self.stat() is not None: + result = self.get_path() + else: + result = srcnode.get_path() + if not Save_Strings: + # We're not at the point where we're saving the string + # representations of FS Nodes (because we haven't finished + # reading the SConscript files and need to have str() return + # things relative to them). That also means we can't yet + # cache values returned (or not returned) by stat(), since + # Python code in the SConscript files might still create + # or otherwise affect the on-disk file. So get rid of the + # values that the underlying stat() method saved. + try: del self._memo['stat'] + except KeyError: pass + if self is not srcnode: + try: del srcnode._memo['stat'] + except KeyError: pass + return result + + rstr = __str__ + + @SCons.Memoize.CountMethodCall + def stat(self): + try: + return self._memo['stat'] + except KeyError: + pass + try: + result = self.fs.stat(self.get_abspath()) + except os.error: + result = None + + self._memo['stat'] = result + return result + + def exists(self): + return SCons.Node._exists_map[self._func_exists](self) + + def rexists(self): + return SCons.Node._rexists_map[self._func_rexists](self) + + def getmtime(self): + st = self.stat() + if st: + return st[stat.ST_MTIME] + else: + return None + + def getsize(self): + st = self.stat() + if st: + return st[stat.ST_SIZE] + else: + return None + + def isdir(self): + st = self.stat() + return st is not None and stat.S_ISDIR(st[stat.ST_MODE]) + + def isfile(self): + st = self.stat() + return st is not None and stat.S_ISREG(st[stat.ST_MODE]) + + if hasattr(os, 'symlink'): + def islink(self): + try: st = self.fs.lstat(self.get_abspath()) + except os.error: return 0 + return stat.S_ISLNK(st[stat.ST_MODE]) + else: + def islink(self): + return 0 # no symlinks + + def is_under(self, dir): + if self is dir: + return 1 + else: + return self.dir.is_under(dir) + + def set_local(self): + self._local = 1 + + def srcnode(self): + """If this node is in a build path, return the node + corresponding to its source file. Otherwise, return + ourself. + """ + srcdir_list = self.dir.srcdir_list() + if srcdir_list: + srcnode = srcdir_list[0].Entry(self.name) + srcnode.must_be_same(self.__class__) + return srcnode + return self + + def get_path(self, dir=None): + """Return path relative to the current working directory of the + Node.FS.Base object that owns us.""" + if not dir: + dir = self.fs.getcwd() + if self == dir: + return '.' + path_elems = self.get_path_elements() + pathname = '' + try: i = path_elems.index(dir) + except ValueError: + for p in path_elems[:-1]: + pathname += p.dirname + else: + for p in path_elems[i+1:-1]: + pathname += p.dirname + return pathname + path_elems[-1].name + + def set_src_builder(self, builder): + """Set the source code builder for this node.""" + self.sbuilder = builder + if not self.has_builder(): + self.builder_set(builder) + + def src_builder(self): + """Fetch the source code builder for this node. + + If there isn't one, we cache the source code builder specified + for the directory (which in turn will cache the value from its + parent directory, and so on up to the file system root). + """ + try: + scb = self.sbuilder + except AttributeError: + scb = self.dir.src_builder() + self.sbuilder = scb + return scb + + def get_abspath(self): + """Get the absolute path of the file.""" + return self.dir.entry_abspath(self.name) + + def get_labspath(self): + """Get the absolute path of the file.""" + return self.dir.entry_labspath(self.name) + + def get_internal_path(self): + if self.dir._path == '.': + return self.name + else: + return self.dir.entry_path(self.name) + + def get_tpath(self): + if self.dir._tpath == '.': + return self.name + else: + return self.dir.entry_tpath(self.name) + + def get_path_elements(self): + return self.dir._path_elements + [self] + + def for_signature(self): + # Return just our name. Even an absolute path would not work, + # because that can change thanks to symlinks or remapped network + # paths. + return self.name + + def get_subst_proxy(self): + try: + return self._proxy + except AttributeError: + ret = EntryProxy(self) + self._proxy = ret + return ret + + def target_from_source(self, prefix, suffix, splitext=SCons.Util.splitext): + """ + + Generates a target entry that corresponds to this entry (usually + a source file) with the specified prefix and suffix. + + Note that this method can be overridden dynamically for generated + files that need different behavior. See Tool/swig.py for + an example. + """ + return SCons.Node._target_from_source_map[self._func_target_from_source](self, prefix, suffix, splitext) + + def _Rfindalldirs_key(self, pathlist): + return pathlist + + @SCons.Memoize.CountDictCall(_Rfindalldirs_key) + def Rfindalldirs(self, pathlist): + """ + Return all of the directories for a given path list, including + corresponding "backing" directories in any repositories. + + The Node lookups are relative to this Node (typically a + directory), so memoizing result saves cycles from looking + up the same path for each target in a given directory. + """ + try: + memo_dict = self._memo['Rfindalldirs'] + except KeyError: + memo_dict = {} + self._memo['Rfindalldirs'] = memo_dict + else: + try: + return memo_dict[pathlist] + except KeyError: + pass + + create_dir_relative_to_self = self.Dir + result = [] + for path in pathlist: + if isinstance(path, SCons.Node.Node): + result.append(path) + else: + dir = create_dir_relative_to_self(path) + result.extend(dir.get_all_rdirs()) + + memo_dict[pathlist] = result + + return result + + def RDirs(self, pathlist): + """Search for a list of directories in the Repository list.""" + cwd = self.cwd or self.fs._cwd + return cwd.Rfindalldirs(pathlist) + + @SCons.Memoize.CountMethodCall + def rentry(self): + try: + return self._memo['rentry'] + except KeyError: + pass + result = self + if not self.exists(): + norm_name = _my_normcase(self.name) + for dir in self.dir.get_all_rdirs(): + try: + node = dir.entries[norm_name] + except KeyError: + if dir.entry_exists_on_disk(self.name): + result = dir.Entry(self.name) + break + self._memo['rentry'] = result + return result + + def _glob1(self, pattern, ondisk=True, source=False, strings=False): + return [] + +# Dict that provides a simple backward compatibility +# layer for the Node attributes 'abspath', 'labspath', +# 'path', 'tpath' and 'path_elements'. +# @see Base.__getattr__ above +node_bwcomp = {'abspath' : Base.get_abspath, + 'labspath' : Base.get_labspath, + 'path' : Base.get_internal_path, + 'tpath' : Base.get_tpath, + 'path_elements' : Base.get_path_elements, + 'suffix' : Base.get_suffix} + +class Entry(Base): + """This is the class for generic Node.FS entries--that is, things + that could be a File or a Dir, but we're just not sure yet. + Consequently, the methods in this class really exist just to + transform their associated object into the right class when the + time comes, and then call the same-named method in the transformed + class.""" + + __slots__ = ['scanner_paths', + 'cachedir_csig', + 'cachesig', + 'repositories', + 'srcdir', + 'entries', + 'searched', + '_sconsign', + 'variant_dirs', + 'root', + 'dirname', + 'on_disk_entries', + 'released_target_info', + 'contentsig'] + + def __init__(self, name, directory, fs): + Base.__init__(self, name, directory, fs) + self._func_exists = 3 + self._func_get_contents = 1 + + def diskcheck_match(self): + pass + + def disambiguate(self, must_exist=None): + """ + """ + if self.isdir(): + self.__class__ = Dir + self._morph() + elif self.isfile(): + self.__class__ = File + self._morph() + self.clear() + else: + # There was nothing on-disk at this location, so look in + # the src directory. + # + # We can't just use self.srcnode() straight away because + # that would create an actual Node for this file in the src + # directory, and there might not be one. Instead, use the + # dir_on_disk() method to see if there's something on-disk + # with that name, in which case we can go ahead and call + # self.srcnode() to create the right type of entry. + srcdir = self.dir.srcnode() + if srcdir != self.dir and \ + srcdir.entry_exists_on_disk(self.name) and \ + self.srcnode().isdir(): + self.__class__ = Dir + self._morph() + elif must_exist: + msg = "No such file or directory: '%s'" % self.get_abspath() + raise SCons.Errors.UserError(msg) + else: + self.__class__ = File + self._morph() + self.clear() + return self + + def rfile(self): + """We're a generic Entry, but the caller is actually looking for + a File at this point, so morph into one.""" + self.__class__ = File + self._morph() + self.clear() + return File.rfile(self) + + def scanner_key(self): + return self.get_suffix() + + def get_contents(self): + """Fetch the contents of the entry. Returns the exact binary + contents of the file.""" + return SCons.Node._get_contents_map[self._func_get_contents](self) + + def get_text_contents(self): + """Fetch the decoded text contents of a Unicode encoded Entry. + + Since this should return the text contents from the file + system, we check to see into what sort of subclass we should + morph this Entry.""" + try: + self = self.disambiguate(must_exist=1) + except SCons.Errors.UserError: + # There was nothing on disk with which to disambiguate + # this entry. Leave it as an Entry, but return a null + # string so calls to get_text_contents() in emitters and + # the like (e.g. in qt.py) don't have to disambiguate by + # hand or catch the exception. + return '' + else: + return self.get_text_contents() + + def must_be_same(self, klass): + """Called to make sure a Node is a Dir. Since we're an + Entry, we can morph into one.""" + if self.__class__ is not klass: + self.__class__ = klass + self._morph() + self.clear() + + # The following methods can get called before the Taskmaster has + # had a chance to call disambiguate() directly to see if this Entry + # should really be a Dir or a File. We therefore use these to call + # disambiguate() transparently (from our caller's point of view). + # + # Right now, this minimal set of methods has been derived by just + # looking at some of the methods that will obviously be called early + # in any of the various Taskmasters' calling sequences, and then + # empirically figuring out which additional methods are necessary + # to make various tests pass. + + def exists(self): + return SCons.Node._exists_map[self._func_exists](self) + + def rel_path(self, other): + d = self.disambiguate() + if d.__class__ is Entry: + raise Exception("rel_path() could not disambiguate File/Dir") + return d.rel_path(other) + + def new_ninfo(self): + return self.disambiguate().new_ninfo() + + def _glob1(self, pattern, ondisk=True, source=False, strings=False): + return self.disambiguate()._glob1(pattern, ondisk, source, strings) + + def get_subst_proxy(self): + return self.disambiguate().get_subst_proxy() + +# This is for later so we can differentiate between Entry the class and Entry +# the method of the FS class. +_classEntry = Entry + + +class LocalFS(object): + """ + This class implements an abstraction layer for operations involving + a local file system. Essentially, this wraps any function in + the os, os.path or shutil modules that we use to actually go do + anything with or to the local file system. + + Note that there's a very good chance we'll refactor this part of + the architecture in some way as we really implement the interface(s) + for remote file system Nodes. For example, the right architecture + might be to have this be a subclass instead of a base class. + Nevertheless, we're using this as a first step in that direction. + + We're not using chdir() yet because the calling subclass method + needs to use os.chdir() directly to avoid recursion. Will we + really need this one? + """ + #def chdir(self, path): + # return os.chdir(path) + def chmod(self, path, mode): + return os.chmod(path, mode) + def copy(self, src, dst): + return shutil.copy(src, dst) + def copy2(self, src, dst): + return shutil.copy2(src, dst) + def exists(self, path): + return os.path.exists(path) + def getmtime(self, path): + return os.path.getmtime(path) + def getsize(self, path): + return os.path.getsize(path) + def isdir(self, path): + return os.path.isdir(path) + def isfile(self, path): + return os.path.isfile(path) + def link(self, src, dst): + return os.link(src, dst) + def lstat(self, path): + return os.lstat(path) + def listdir(self, path): + return os.listdir(path) + def makedirs(self, path): + return os.makedirs(path) + def mkdir(self, path): + return os.mkdir(path) + def rename(self, old, new): + return os.rename(old, new) + def stat(self, path): + return os.stat(path) + def symlink(self, src, dst): + return os.symlink(src, dst) + def open(self, path): + return open(path) + def unlink(self, path): + return os.unlink(path) + + if hasattr(os, 'symlink'): + def islink(self, path): + return os.path.islink(path) + else: + def islink(self, path): + return 0 # no symlinks + + if hasattr(os, 'readlink'): + def readlink(self, file): + return os.readlink(file) + else: + def readlink(self, file): + return '' + + +class FS(LocalFS): + + def __init__(self, path = None): + """Initialize the Node.FS subsystem. + + The supplied path is the top of the source tree, where we + expect to find the top-level build file. If no path is + supplied, the current directory is the default. + + The path argument must be a valid absolute path. + """ + if SCons.Debug.track_instances: logInstanceCreation(self, 'Node.FS') + + self._memo = {} + + self.Root = {} + self.SConstruct_dir = None + self.max_drift = default_max_drift + + self.Top = None + if path is None: + self.pathTop = os.getcwd() + else: + self.pathTop = path + self.defaultDrive = _my_normcase(_my_splitdrive(self.pathTop)[0]) + + self.Top = self.Dir(self.pathTop) + self.Top._path = '.' + self.Top._tpath = '.' + self._cwd = self.Top + + DirNodeInfo.fs = self + FileNodeInfo.fs = self + + def set_SConstruct_dir(self, dir): + self.SConstruct_dir = dir + + def get_max_drift(self): + return self.max_drift + + def set_max_drift(self, max_drift): + self.max_drift = max_drift + + def getcwd(self): + if hasattr(self, "_cwd"): + return self._cwd + else: + return "" + + def chdir(self, dir, change_os_dir=0): + """Change the current working directory for lookups. + If change_os_dir is true, we will also change the "real" cwd + to match. + """ + curr=self._cwd + try: + if dir is not None: + self._cwd = dir + if change_os_dir: + os.chdir(dir.get_abspath()) + except OSError: + self._cwd = curr + raise + + def get_root(self, drive): + """ + Returns the root directory for the specified drive, creating + it if necessary. + """ + drive = _my_normcase(drive) + try: + return self.Root[drive] + except KeyError: + root = RootDir(drive, self) + self.Root[drive] = root + if not drive: + self.Root[self.defaultDrive] = root + elif drive == self.defaultDrive: + self.Root[''] = root + return root + + def _lookup(self, p, directory, fsclass, create=1): + """ + The generic entry point for Node lookup with user-supplied data. + + This translates arbitrary input into a canonical Node.FS object + of the specified fsclass. The general approach for strings is + to turn it into a fully normalized absolute path and then call + the root directory's lookup_abs() method for the heavy lifting. + + If the path name begins with '#', it is unconditionally + interpreted relative to the top-level directory of this FS. '#' + is treated as a synonym for the top-level SConstruct directory, + much like '~' is treated as a synonym for the user's home + directory in a UNIX shell. So both '#foo' and '#/foo' refer + to the 'foo' subdirectory underneath the top-level SConstruct + directory. + + If the path name is relative, then the path is looked up relative + to the specified directory, or the current directory (self._cwd, + typically the SConscript directory) if the specified directory + is None. + """ + if isinstance(p, Base): + # It's already a Node.FS object. Make sure it's the right + # class and return. + p.must_be_same(fsclass) + return p + # str(p) in case it's something like a proxy object + p = str(p) + + if not os_sep_is_slash: + p = p.replace(OS_SEP, '/') + + if p[0:1] == '#': + # There was an initial '#', so we strip it and override + # whatever directory they may have specified with the + # top-level SConstruct directory. + p = p[1:] + directory = self.Top + + # There might be a drive letter following the + # '#'. Although it is not described in the SCons man page, + # the regression test suite explicitly tests for that + # syntax. It seems to mean the following thing: + # + # Assuming the the SCons top dir is in C:/xxx/yyy, + # '#X:/toto' means X:/xxx/yyy/toto. + # + # i.e. it assumes that the X: drive has a directory + # structure similar to the one found on drive C:. + if do_splitdrive: + drive, p = _my_splitdrive(p) + if drive: + root = self.get_root(drive) + else: + root = directory.root + else: + root = directory.root + + # We can only strip trailing after splitting the drive + # since the drive might the UNC '//' prefix. + p = p.strip('/') + + needs_normpath = needs_normpath_match(p) + + # The path is relative to the top-level SCons directory. + if p in ('', '.'): + p = directory.get_labspath() + else: + p = directory.get_labspath() + '/' + p + else: + if do_splitdrive: + drive, p = _my_splitdrive(p) + if drive and not p: + # This causes a naked drive letter to be treated + # as a synonym for the root directory on that + # drive. + p = '/' + else: + drive = '' + + # We can only strip trailing '/' since the drive might the + # UNC '//' prefix. + if p != '/': + p = p.rstrip('/') + + needs_normpath = needs_normpath_match(p) + + if p[0:1] == '/': + # Absolute path + root = self.get_root(drive) + else: + # This is a relative lookup or to the current directory + # (the path name is not absolute). Add the string to the + # appropriate directory lookup path, after which the whole + # thing gets normalized. + if directory: + if not isinstance(directory, Dir): + directory = self.Dir(directory) + else: + directory = self._cwd + + if p in ('', '.'): + p = directory.get_labspath() + else: + p = directory.get_labspath() + '/' + p + + if drive: + root = self.get_root(drive) + else: + root = directory.root + + if needs_normpath is not None: + # Normalize a pathname. Will return the same result for + # equivalent paths. + # + # We take advantage of the fact that we have an absolute + # path here for sure. In addition, we know that the + # components of lookup path are separated by slashes at + # this point. Because of this, this code is about 2X + # faster than calling os.path.normpath() followed by + # replacing os.sep with '/' again. + ins = p.split('/')[1:] + outs = [] + for d in ins: + if d == '..': + try: + outs.pop() + except IndexError: + pass + elif d not in ('', '.'): + outs.append(d) + p = '/' + '/'.join(outs) + + return root._lookup_abs(p, fsclass, create) + + def Entry(self, name, directory = None, create = 1): + """Look up or create a generic Entry node with the specified name. + If the name is a relative path (begins with ./, ../, or a file + name), then it is looked up relative to the supplied directory + node, or to the top level directory of the FS (supplied at + construction time) if no directory is supplied. + """ + return self._lookup(name, directory, Entry, create) + + def File(self, name, directory = None, create = 1): + """Look up or create a File node with the specified name. If + the name is a relative path (begins with ./, ../, or a file name), + then it is looked up relative to the supplied directory node, + or to the top level directory of the FS (supplied at construction + time) if no directory is supplied. + + This method will raise TypeError if a directory is found at the + specified path. + """ + return self._lookup(name, directory, File, create) + + def Dir(self, name, directory = None, create = True): + """Look up or create a Dir node with the specified name. If + the name is a relative path (begins with ./, ../, or a file name), + then it is looked up relative to the supplied directory node, + or to the top level directory of the FS (supplied at construction + time) if no directory is supplied. + + This method will raise TypeError if a normal file is found at the + specified path. + """ + return self._lookup(name, directory, Dir, create) + + def VariantDir(self, variant_dir, src_dir, duplicate=1): + """Link the supplied variant directory to the source directory + for purposes of building files.""" + + if not isinstance(src_dir, SCons.Node.Node): + src_dir = self.Dir(src_dir) + if not isinstance(variant_dir, SCons.Node.Node): + variant_dir = self.Dir(variant_dir) + if src_dir.is_under(variant_dir): + raise SCons.Errors.UserError("Source directory cannot be under variant directory.") + if variant_dir.srcdir: + if variant_dir.srcdir == src_dir: + return # We already did this. + raise SCons.Errors.UserError("'%s' already has a source directory: '%s'."%(variant_dir, variant_dir.srcdir)) + variant_dir.link(src_dir, duplicate) + + def Repository(self, *dirs): + """Specify Repository directories to search.""" + for d in dirs: + if not isinstance(d, SCons.Node.Node): + d = self.Dir(d) + self.Top.addRepository(d) + + def PyPackageDir(self, modulename): + """Locate the directory of a given python module name + + For example scons might resolve to + Windows: C:\Python27\Lib\site-packages\scons-2.5.1 + Linux: /usr/lib/scons + + This can be useful when we want to determine a toolpath based on a python module name""" + + dirpath = '' + if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and sys.version_info[1] in (0,1,2,3,4)): + # Python2 Code + import imp + splitname = modulename.split('.') + srchpths = sys.path + for item in splitname: + file, path, desc = imp.find_module(item, srchpths) + if file is not None: + path = os.path.dirname(path) + srchpths = [path] + dirpath = path + else: + # Python3 Code + import importlib.util + modspec = importlib.util.find_spec(modulename) + dirpath = os.path.dirname(modspec.origin) + return self._lookup(dirpath, None, Dir, True) + + + def variant_dir_target_climb(self, orig, dir, tail): + """Create targets in corresponding variant directories + + Climb the directory tree, and look up path names + relative to any linked variant directories we find. + + Even though this loops and walks up the tree, we don't memoize + the return value because this is really only used to process + the command-line targets. + """ + targets = [] + message = None + fmt = "building associated VariantDir targets: %s" + start_dir = dir + while dir: + for bd in dir.variant_dirs: + if start_dir.is_under(bd): + # If already in the build-dir location, don't reflect + return [orig], fmt % str(orig) + p = os.path.join(bd._path, *tail) + targets.append(self.Entry(p)) + tail = [dir.name] + tail + dir = dir.up() + if targets: + message = fmt % ' '.join(map(str, targets)) + return targets, message + + def Glob(self, pathname, ondisk=True, source=True, strings=False, exclude=None, cwd=None): + """ + Globs + + This is mainly a shim layer + """ + if cwd is None: + cwd = self.getcwd() + return cwd.glob(pathname, ondisk, source, strings, exclude) + +class DirNodeInfo(SCons.Node.NodeInfoBase): + __slots__ = () + # This should get reset by the FS initialization. + current_version_id = 2 + + fs = None + + def str_to_node(self, s): + top = self.fs.Top + root = top.root + if do_splitdrive: + drive, s = _my_splitdrive(s) + if drive: + root = self.fs.get_root(drive) + if not os.path.isabs(s): + s = top.get_labspath() + '/' + s + return root._lookup_abs(s, Entry) + +class DirBuildInfo(SCons.Node.BuildInfoBase): + __slots__ = () + current_version_id = 2 + +glob_magic_check = re.compile('[*?[]') + +def has_glob_magic(s): + return glob_magic_check.search(s) is not None + +class Dir(Base): + """A class for directories in a file system. + """ + + __slots__ = ['scanner_paths', + 'cachedir_csig', + 'cachesig', + 'repositories', + 'srcdir', + 'entries', + 'searched', + '_sconsign', + 'variant_dirs', + 'root', + 'dirname', + 'on_disk_entries', + 'released_target_info', + 'contentsig'] + + NodeInfo = DirNodeInfo + BuildInfo = DirBuildInfo + + def __init__(self, name, directory, fs): + if SCons.Debug.track_instances: logInstanceCreation(self, 'Node.FS.Dir') + Base.__init__(self, name, directory, fs) + self._morph() + + def _morph(self): + """Turn a file system Node (either a freshly initialized directory + object or a separate Entry object) into a proper directory object. + + Set up this directory's entries and hook it into the file + system tree. Specify that directories (this Node) don't use + signatures for calculating whether they're current. + """ + + self.repositories = [] + self.srcdir = None + + self.entries = {} + self.entries['.'] = self + self.entries['..'] = self.dir + self.cwd = self + self.searched = 0 + self._sconsign = None + self.variant_dirs = [] + self.root = self.dir.root + self.changed_since_last_build = 3 + self._func_sconsign = 1 + self._func_exists = 2 + self._func_get_contents = 2 + + self._abspath = SCons.Util.silent_intern(self.dir.entry_abspath(self.name)) + self._labspath = SCons.Util.silent_intern(self.dir.entry_labspath(self.name)) + if self.dir._path == '.': + self._path = SCons.Util.silent_intern(self.name) + else: + self._path = SCons.Util.silent_intern(self.dir.entry_path(self.name)) + if self.dir._tpath == '.': + self._tpath = SCons.Util.silent_intern(self.name) + else: + self._tpath = SCons.Util.silent_intern(self.dir.entry_tpath(self.name)) + self._path_elements = self.dir._path_elements + [self] + + # For directories, we make a difference between the directory + # 'name' and the directory 'dirname'. The 'name' attribute is + # used when we need to print the 'name' of the directory or + # when we it is used as the last part of a path. The 'dirname' + # is used when the directory is not the last element of the + # path. The main reason for making that distinction is that + # for RoorDir's the dirname can not be easily inferred from + # the name. For example, we have to add a '/' after a drive + # letter but not after a UNC path prefix ('//'). + self.dirname = self.name + OS_SEP + + # Don't just reset the executor, replace its action list, + # because it might have some pre-or post-actions that need to + # be preserved. + # + # But don't reset the executor if there is a non-null executor + # attached already. The existing executor might have other + # targets, in which case replacing the action list with a + # Mkdir action is a big mistake. + if not hasattr(self, 'executor'): + self.builder = get_MkdirBuilder() + self.get_executor().set_action_list(self.builder.action) + else: + # Prepend MkdirBuilder action to existing action list + l = self.get_executor().action_list + a = get_MkdirBuilder().action + l.insert(0, a) + self.get_executor().set_action_list(l) + + def diskcheck_match(self): + diskcheck_match(self, self.isfile, + "File %s found where directory expected.") + + def __clearRepositoryCache(self, duplicate=None): + """Called when we change the repository(ies) for a directory. + This clears any cached information that is invalidated by changing + the repository.""" + + for node in list(self.entries.values()): + if node != self.dir: + if node != self and isinstance(node, Dir): + node.__clearRepositoryCache(duplicate) + else: + node.clear() + try: + del node._srcreps + except AttributeError: + pass + if duplicate is not None: + node.duplicate=duplicate + + def __resetDuplicate(self, node): + if node != self: + node.duplicate = node.get_dir().duplicate + + def Entry(self, name): + """ + Looks up or creates an entry node named 'name' relative to + this directory. + """ + return self.fs.Entry(name, self) + + def Dir(self, name, create=True): + """ + Looks up or creates a directory node named 'name' relative to + this directory. + """ + return self.fs.Dir(name, self, create) + + def File(self, name): + """ + Looks up or creates a file node named 'name' relative to + this directory. + """ + return self.fs.File(name, self) + + def link(self, srcdir, duplicate): + """Set this directory as the variant directory for the + supplied source directory.""" + self.srcdir = srcdir + self.duplicate = duplicate + self.__clearRepositoryCache(duplicate) + srcdir.variant_dirs.append(self) + + def getRepositories(self): + """Returns a list of repositories for this directory. + """ + if self.srcdir and not self.duplicate: + return self.srcdir.get_all_rdirs() + self.repositories + return self.repositories + + @SCons.Memoize.CountMethodCall + def get_all_rdirs(self): + try: + return list(self._memo['get_all_rdirs']) + except KeyError: + pass + + result = [self] + fname = '.' + dir = self + while dir: + for rep in dir.getRepositories(): + result.append(rep.Dir(fname)) + if fname == '.': + fname = dir.name + else: + fname = dir.name + OS_SEP + fname + dir = dir.up() + + self._memo['get_all_rdirs'] = list(result) + + return result + + def addRepository(self, dir): + if dir != self and not dir in self.repositories: + self.repositories.append(dir) + dir._tpath = '.' + self.__clearRepositoryCache() + + def up(self): + return self.dir + + def _rel_path_key(self, other): + return str(other) + + @SCons.Memoize.CountDictCall(_rel_path_key) + def rel_path(self, other): + """Return a path to "other" relative to this directory. + """ + + # This complicated and expensive method, which constructs relative + # paths between arbitrary Node.FS objects, is no longer used + # by SCons itself. It was introduced to store dependency paths + # in .sconsign files relative to the target, but that ended up + # being significantly inefficient. + # + # We're continuing to support the method because some SConstruct + # files out there started using it when it was available, and + # we're all about backwards compatibility.. + + try: + memo_dict = self._memo['rel_path'] + except KeyError: + memo_dict = {} + self._memo['rel_path'] = memo_dict + else: + try: + return memo_dict[other] + except KeyError: + pass + + if self is other: + result = '.' + + elif not other in self._path_elements: + try: + other_dir = other.get_dir() + except AttributeError: + result = str(other) + else: + if other_dir is None: + result = other.name + else: + dir_rel_path = self.rel_path(other_dir) + if dir_rel_path == '.': + result = other.name + else: + result = dir_rel_path + OS_SEP + other.name + else: + i = self._path_elements.index(other) + 1 + + path_elems = ['..'] * (len(self._path_elements) - i) \ + + [n.name for n in other._path_elements[i:]] + + result = OS_SEP.join(path_elems) + + memo_dict[other] = result + + return result + + def get_env_scanner(self, env, kw={}): + import SCons.Defaults + return SCons.Defaults.DirEntryScanner + + def get_target_scanner(self): + import SCons.Defaults + return SCons.Defaults.DirEntryScanner + + def get_found_includes(self, env, scanner, path): + """Return this directory's implicit dependencies. + + We don't bother caching the results because the scan typically + shouldn't be requested more than once (as opposed to scanning + .h file contents, which can be requested as many times as the + files is #included by other files). + """ + if not scanner: + return [] + # Clear cached info for this Dir. If we already visited this + # directory on our walk down the tree (because we didn't know at + # that point it was being used as the source for another Node) + # then we may have calculated build signature before realizing + # we had to scan the disk. Now that we have to, though, we need + # to invalidate the old calculated signature so that any node + # dependent on our directory structure gets one that includes + # info about everything on disk. + self.clear() + return scanner(self, env, path) + + # + # Taskmaster interface subsystem + # + + def prepare(self): + pass + + def build(self, **kw): + """A null "builder" for directories.""" + global MkdirBuilder + if self.builder is not MkdirBuilder: + SCons.Node.Node.build(self, **kw) + + # + # + # + + def _create(self): + """Create this directory, silently and without worrying about + whether the builder is the default or not.""" + listDirs = [] + parent = self + while parent: + if parent.exists(): + break + listDirs.append(parent) + p = parent.up() + if p is None: + # Don't use while: - else: for this condition because + # if so, then parent is None and has no .path attribute. + raise SCons.Errors.StopError(parent._path) + parent = p + listDirs.reverse() + for dirnode in listDirs: + try: + # Don't call dirnode.build(), call the base Node method + # directly because we definitely *must* create this + # directory. The dirnode.build() method will suppress + # the build if it's the default builder. + SCons.Node.Node.build(dirnode) + dirnode.get_executor().nullify() + # The build() action may or may not have actually + # created the directory, depending on whether the -n + # option was used or not. Delete the _exists and + # _rexists attributes so they can be reevaluated. + dirnode.clear() + except OSError: + pass + + def multiple_side_effect_has_builder(self): + global MkdirBuilder + return self.builder is not MkdirBuilder and self.has_builder() + + def alter_targets(self): + """Return any corresponding targets in a variant directory. + """ + return self.fs.variant_dir_target_climb(self, self, []) + + def scanner_key(self): + """A directory does not get scanned.""" + return None + + def get_text_contents(self): + """We already emit things in text, so just return the binary + version.""" + return self.get_contents() + + def get_contents(self): + """Return content signatures and names of all our children + separated by new-lines. Ensure that the nodes are sorted.""" + return SCons.Node._get_contents_map[self._func_get_contents](self) + + def get_csig(self): + """Compute the content signature for Directory nodes. In + general, this is not needed and the content signature is not + stored in the DirNodeInfo. However, if get_contents on a Dir + node is called which has a child directory, the child + directory should return the hash of its contents.""" + contents = self.get_contents() + return SCons.Util.MD5signature(contents) + + def do_duplicate(self, src): + pass + + def is_up_to_date(self): + """If any child is not up-to-date, then this directory isn't, + either.""" + if self.builder is not MkdirBuilder and not self.exists(): + return 0 + up_to_date = SCons.Node.up_to_date + for kid in self.children(): + if kid.get_state() > up_to_date: + return 0 + return 1 + + def rdir(self): + if not self.exists(): + norm_name = _my_normcase(self.name) + for dir in self.dir.get_all_rdirs(): + try: node = dir.entries[norm_name] + except KeyError: node = dir.dir_on_disk(self.name) + if node and node.exists() and \ + (isinstance(dir, Dir) or isinstance(dir, Entry)): + return node + return self + + def sconsign(self): + """Return the .sconsign file info for this directory. """ + return _sconsign_map[self._func_sconsign](self) + + def srcnode(self): + """Dir has a special need for srcnode()...if we + have a srcdir attribute set, then that *is* our srcnode.""" + if self.srcdir: + return self.srcdir + return Base.srcnode(self) + + def get_timestamp(self): + """Return the latest timestamp from among our children""" + stamp = 0 + for kid in self.children(): + if kid.get_timestamp() > stamp: + stamp = kid.get_timestamp() + return stamp + + def get_abspath(self): + """Get the absolute path of the file.""" + return self._abspath + + def get_labspath(self): + """Get the absolute path of the file.""" + return self._labspath + + def get_internal_path(self): + return self._path + + def get_tpath(self): + return self._tpath + + def get_path_elements(self): + return self._path_elements + + def entry_abspath(self, name): + return self._abspath + OS_SEP + name + + def entry_labspath(self, name): + return self._labspath + '/' + name + + def entry_path(self, name): + return self._path + OS_SEP + name + + def entry_tpath(self, name): + return self._tpath + OS_SEP + name + + def entry_exists_on_disk(self, name): + """ Searches through the file/dir entries of the current + directory, and returns True if a physical entry with the given + name could be found. + + @see rentry_exists_on_disk + """ + try: + d = self.on_disk_entries + except AttributeError: + d = {} + try: + entries = os.listdir(self._abspath) + except OSError: + pass + else: + for entry in map(_my_normcase, entries): + d[entry] = True + self.on_disk_entries = d + if sys.platform == 'win32' or sys.platform == 'cygwin': + name = _my_normcase(name) + result = d.get(name) + if result is None: + # Belt-and-suspenders for Windows: check directly for + # 8.3 file names that don't show up in os.listdir(). + result = os.path.exists(self._abspath + OS_SEP + name) + d[name] = result + return result + else: + return name in d + + def rentry_exists_on_disk(self, name): + """ Searches through the file/dir entries of the current + *and* all its remote directories (repos), and returns + True if a physical entry with the given name could be found. + The local directory (self) gets searched first, so + repositories take a lower precedence regarding the + searching order. + + @see entry_exists_on_disk + """ + + rentry_exists = self.entry_exists_on_disk(name) + if not rentry_exists: + # Search through the repository folders + norm_name = _my_normcase(name) + for rdir in self.get_all_rdirs(): + try: + node = rdir.entries[norm_name] + if node: + rentry_exists = True + break + except KeyError: + if rdir.entry_exists_on_disk(name): + rentry_exists = True + break + return rentry_exists + + @SCons.Memoize.CountMethodCall + def srcdir_list(self): + try: + return self._memo['srcdir_list'] + except KeyError: + pass + + result = [] + + dirname = '.' + dir = self + while dir: + if dir.srcdir: + result.append(dir.srcdir.Dir(dirname)) + dirname = dir.name + OS_SEP + dirname + dir = dir.up() + + self._memo['srcdir_list'] = result + + return result + + def srcdir_duplicate(self, name): + for dir in self.srcdir_list(): + if self.is_under(dir): + # We shouldn't source from something in the build path; + # variant_dir is probably under src_dir, in which case + # we are reflecting. + break + if dir.entry_exists_on_disk(name): + srcnode = dir.Entry(name).disambiguate() + if self.duplicate: + node = self.Entry(name).disambiguate() + node.do_duplicate(srcnode) + return node + else: + return srcnode + return None + + def _srcdir_find_file_key(self, filename): + return filename + + @SCons.Memoize.CountDictCall(_srcdir_find_file_key) + def srcdir_find_file(self, filename): + try: + memo_dict = self._memo['srcdir_find_file'] + except KeyError: + memo_dict = {} + self._memo['srcdir_find_file'] = memo_dict + else: + try: + return memo_dict[filename] + except KeyError: + pass + + def func(node): + if (isinstance(node, File) or isinstance(node, Entry)) and \ + (node.is_derived() or node.exists()): + return node + return None + + norm_name = _my_normcase(filename) + + for rdir in self.get_all_rdirs(): + try: node = rdir.entries[norm_name] + except KeyError: node = rdir.file_on_disk(filename) + else: node = func(node) + if node: + result = (node, self) + memo_dict[filename] = result + return result + + for srcdir in self.srcdir_list(): + for rdir in srcdir.get_all_rdirs(): + try: node = rdir.entries[norm_name] + except KeyError: node = rdir.file_on_disk(filename) + else: node = func(node) + if node: + result = (File(filename, self, self.fs), srcdir) + memo_dict[filename] = result + return result + + result = (None, None) + memo_dict[filename] = result + return result + + def dir_on_disk(self, name): + if self.entry_exists_on_disk(name): + try: return self.Dir(name) + except TypeError: pass + node = self.srcdir_duplicate(name) + if isinstance(node, File): + return None + return node + + def file_on_disk(self, name): + if self.entry_exists_on_disk(name): + try: return self.File(name) + except TypeError: pass + node = self.srcdir_duplicate(name) + if isinstance(node, Dir): + return None + return node + + def walk(self, func, arg): + """ + Walk this directory tree by calling the specified function + for each directory in the tree. + + This behaves like the os.path.walk() function, but for in-memory + Node.FS.Dir objects. The function takes the same arguments as + the functions passed to os.path.walk(): + + func(arg, dirname, fnames) + + Except that "dirname" will actually be the directory *Node*, + not the string. The '.' and '..' entries are excluded from + fnames. The fnames list may be modified in-place to filter the + subdirectories visited or otherwise impose a specific order. + The "arg" argument is always passed to func() and may be used + in any way (or ignored, passing None is common). + """ + entries = self.entries + names = list(entries.keys()) + names.remove('.') + names.remove('..') + func(arg, self, names) + for dirname in [n for n in names if isinstance(entries[n], Dir)]: + entries[dirname].walk(func, arg) + + def glob(self, pathname, ondisk=True, source=False, strings=False, exclude=None): + """ + Returns a list of Nodes (or strings) matching a specified + pathname pattern. + + Pathname patterns follow UNIX shell semantics: * matches + any-length strings of any characters, ? matches any character, + and [] can enclose lists or ranges of characters. Matches do + not span directory separators. + + The matches take into account Repositories, returning local + Nodes if a corresponding entry exists in a Repository (either + an in-memory Node or something on disk). + + By defafult, the glob() function matches entries that exist + on-disk, in addition to in-memory Nodes. Setting the "ondisk" + argument to False (or some other non-true value) causes the glob() + function to only match in-memory Nodes. The default behavior is + to return both the on-disk and in-memory Nodes. + + The "source" argument, when true, specifies that corresponding + source Nodes must be returned if you're globbing in a build + directory (initialized with VariantDir()). The default behavior + is to return Nodes local to the VariantDir(). + + The "strings" argument, when true, returns the matches as strings, + not Nodes. The strings are path names relative to this directory. + + The "exclude" argument, if not None, must be a pattern or a list + of patterns following the same UNIX shell semantics. + Elements matching a least one pattern of this list will be excluded + from the result. + + The underlying algorithm is adapted from the glob.glob() function + in the Python library (but heavily modified), and uses fnmatch() + under the covers. + """ + dirname, basename = os.path.split(pathname) + if not dirname: + result = self._glob1(basename, ondisk, source, strings) + else: + if has_glob_magic(dirname): + list = self.glob(dirname, ondisk, source, False, exclude) + else: + list = [self.Dir(dirname, create=True)] + result = [] + for dir in list: + r = dir._glob1(basename, ondisk, source, strings) + if strings: + r = [os.path.join(str(dir), x) for x in r] + result.extend(r) + if exclude: + excludes = [] + excludeList = SCons.Util.flatten(exclude) + for x in excludeList: + r = self.glob(x, ondisk, source, strings) + excludes.extend(r) + result = [x for x in result if not any(fnmatch.fnmatch(str(x), str(e)) for e in SCons.Util.flatten(excludes))] + return sorted(result, key=lambda a: str(a)) + + def _glob1(self, pattern, ondisk=True, source=False, strings=False): + """ + Globs for and returns a list of entry names matching a single + pattern in this directory. + + This searches any repositories and source directories for + corresponding entries and returns a Node (or string) relative + to the current directory if an entry is found anywhere. + + TODO: handle pattern with no wildcard + """ + search_dir_list = self.get_all_rdirs() + for srcdir in self.srcdir_list(): + search_dir_list.extend(srcdir.get_all_rdirs()) + + selfEntry = self.Entry + names = [] + for dir in search_dir_list: + # We use the .name attribute from the Node because the keys of + # the dir.entries dictionary are normalized (that is, all upper + # case) on case-insensitive systems like Windows. + node_names = [ v.name for k, v in dir.entries.items() + if k not in ('.', '..') ] + names.extend(node_names) + if not strings: + # Make sure the working directory (self) actually has + # entries for all Nodes in repositories or variant dirs. + for name in node_names: selfEntry(name) + if ondisk: + try: + disk_names = os.listdir(dir._abspath) + except os.error: + continue + names.extend(disk_names) + if not strings: + # We're going to return corresponding Nodes in + # the local directory, so we need to make sure + # those Nodes exist. We only want to create + # Nodes for the entries that will match the + # specified pattern, though, which means we + # need to filter the list here, even though + # the overall list will also be filtered later, + # after we exit this loop. + if pattern[0] != '.': + disk_names = [x for x in disk_names if x[0] != '.'] + disk_names = fnmatch.filter(disk_names, pattern) + dirEntry = dir.Entry + for name in disk_names: + # Add './' before disk filename so that '#' at + # beginning of filename isn't interpreted. + name = './' + name + node = dirEntry(name).disambiguate() + n = selfEntry(name) + if n.__class__ != node.__class__: + n.__class__ = node.__class__ + n._morph() + + names = set(names) + if pattern[0] != '.': + names = [x for x in names if x[0] != '.'] + names = fnmatch.filter(names, pattern) + + if strings: + return names + + return [self.entries[_my_normcase(n)] for n in names] + +class RootDir(Dir): + """A class for the root directory of a file system. + + This is the same as a Dir class, except that the path separator + ('/' or '\\') is actually part of the name, so we don't need to + add a separator when creating the path names of entries within + this directory. + """ + + __slots__ = ['_lookupDict'] + + def __init__(self, drive, fs): + if SCons.Debug.track_instances: logInstanceCreation(self, 'Node.FS.RootDir') + SCons.Node.Node.__init__(self) + + # Handle all the types of drives: + if drive == '': + # No drive, regular UNIX root or Windows default drive. + name = OS_SEP + dirname = OS_SEP + elif drive == '//': + # UNC path + name = UNC_PREFIX + dirname = UNC_PREFIX + else: + # Windows drive letter + name = drive + dirname = drive + OS_SEP + + # Filename with extension as it was specified when the object was + # created; to obtain filesystem path, use Python str() function + self.name = SCons.Util.silent_intern(name) + self.fs = fs #: Reference to parent Node.FS object + + self._path_elements = [self] + self.dir = self + self._func_rexists = 2 + self._func_target_from_source = 1 + self.store_info = 1 + + # Now set our paths to what we really want them to be. The + # name should already contain any necessary separators, such + # as the initial drive letter (the name) plus the directory + # separator, except for the "lookup abspath," which does not + # have the drive letter. + self._abspath = dirname + self._labspath = '' + self._path = dirname + self._tpath = dirname + self.dirname = dirname + + self._morph() + + self.duplicate = 0 + self._lookupDict = {} + + self._lookupDict[''] = self + self._lookupDict['/'] = self + self.root = self + # The // entry is necessary because os.path.normpath() + # preserves double slashes at the beginning of a path on Posix + # platforms. + if not has_unc: + self._lookupDict['//'] = self + + def _morph(self): + """Turn a file system Node (either a freshly initialized directory + object or a separate Entry object) into a proper directory object. + + Set up this directory's entries and hook it into the file + system tree. Specify that directories (this Node) don't use + signatures for calculating whether they're current. + """ + + self.repositories = [] + self.srcdir = None + + self.entries = {} + self.entries['.'] = self + self.entries['..'] = self.dir + self.cwd = self + self.searched = 0 + self._sconsign = None + self.variant_dirs = [] + self.changed_since_last_build = 3 + self._func_sconsign = 1 + self._func_exists = 2 + self._func_get_contents = 2 + + # Don't just reset the executor, replace its action list, + # because it might have some pre-or post-actions that need to + # be preserved. + # + # But don't reset the executor if there is a non-null executor + # attached already. The existing executor might have other + # targets, in which case replacing the action list with a + # Mkdir action is a big mistake. + if not hasattr(self, 'executor'): + self.builder = get_MkdirBuilder() + self.get_executor().set_action_list(self.builder.action) + else: + # Prepend MkdirBuilder action to existing action list + l = self.get_executor().action_list + a = get_MkdirBuilder().action + l.insert(0, a) + self.get_executor().set_action_list(l) + + + def must_be_same(self, klass): + if klass is Dir: + return + Base.must_be_same(self, klass) + + def _lookup_abs(self, p, klass, create=1): + """ + Fast (?) lookup of a *normalized* absolute path. + + This method is intended for use by internal lookups with + already-normalized path data. For general-purpose lookups, + use the FS.Entry(), FS.Dir() or FS.File() methods. + + The caller is responsible for making sure we're passed a + normalized absolute path; we merely let Python's dictionary look + up and return the One True Node.FS object for the path. + + If a Node for the specified "p" doesn't already exist, and + "create" is specified, the Node may be created after recursive + invocation to find or create the parent directory or directories. + """ + k = _my_normcase(p) + try: + result = self._lookupDict[k] + except KeyError: + if not create: + msg = "No such file or directory: '%s' in '%s' (and create is False)" % (p, str(self)) + raise SCons.Errors.UserError(msg) + # There is no Node for this path name, and we're allowed + # to create it. + dir_name, file_name = p.rsplit('/',1) + dir_node = self._lookup_abs(dir_name, Dir) + result = klass(file_name, dir_node, self.fs) + + # Double-check on disk (as configured) that the Node we + # created matches whatever is out there in the real world. + result.diskcheck_match() + + self._lookupDict[k] = result + dir_node.entries[_my_normcase(file_name)] = result + dir_node.implicit = None + else: + # There is already a Node for this path name. Allow it to + # complain if we were looking for an inappropriate type. + result.must_be_same(klass) + return result + + def __str__(self): + return self._abspath + + def entry_abspath(self, name): + return self._abspath + name + + def entry_labspath(self, name): + return '/' + name + + def entry_path(self, name): + return self._path + name + + def entry_tpath(self, name): + return self._tpath + name + + def is_under(self, dir): + if self is dir: + return 1 + else: + return 0 + + def up(self): + return None + + def get_dir(self): + return None + + def src_builder(self): + return _null + + +class FileNodeInfo(SCons.Node.NodeInfoBase): + __slots__ = ('csig', 'timestamp', 'size') + current_version_id = 2 + + field_list = ['csig', 'timestamp', 'size'] + + # This should get reset by the FS initialization. + fs = None + + def str_to_node(self, s): + top = self.fs.Top + root = top.root + if do_splitdrive: + drive, s = _my_splitdrive(s) + if drive: + root = self.fs.get_root(drive) + if not os.path.isabs(s): + s = top.get_labspath() + '/' + s + return root._lookup_abs(s, Entry) + + def __getstate__(self): + """ + Return all fields that shall be pickled. Walk the slots in the class + hierarchy and add those to the state dictionary. If a '__dict__' slot is + available, copy all entries to the dictionary. Also include the version + id, which is fixed for all instances of a class. + """ + state = getattr(self, '__dict__', {}).copy() + for obj in type(self).mro(): + for name in getattr(obj,'__slots__',()): + if hasattr(self, name): + state[name] = getattr(self, name) + + state['_version_id'] = self.current_version_id + try: + del state['__weakref__'] + except KeyError: + pass + + return state + + def __setstate__(self, state): + """ + Restore the attributes from a pickled state. + """ + # TODO check or discard version + del state['_version_id'] + for key, value in state.items(): + if key not in ('__weakref__',): + setattr(self, key, value) + + def __eq__(self, other): + return self.csig == other.csig and self.timestamp == other.timestamp and self.size == other.size + + def __ne__(self, other): + return not self.__eq__(other) + + +class FileBuildInfo(SCons.Node.BuildInfoBase): + """ + This is info loaded from sconsign. + + Attributes unique to FileBuildInfo: + dependency_map : Caches file->csig mapping + for all dependencies. Currently this is only used when using + MD5-timestamp decider. + It's used to ensure that we copy the correct + csig from previous build to be written to .sconsign when current build + is done. Previously the matching of csig to file was strictly by order + they appeared in bdepends, bsources, or bimplicit, and so a change in order + or count of any of these could yield writing wrong csig, and then false positive + rebuilds + """ + __slots__ = ('dependency_map') + current_version_id = 2 + + def __setattr__(self, key, value): + + # If any attributes are changed in FileBuildInfo, we need to + # invalidate the cached map of file name to content signature + # heald in dependency_map. Currently only used with + # MD5-timestamp decider + if key != 'dependency_map' and hasattr(self, 'dependency_map'): + del self.dependency_map + + return super(FileBuildInfo, self).__setattr__(key, value) + + def convert_to_sconsign(self): + """ + Converts this FileBuildInfo object for writing to a .sconsign file + + This replaces each Node in our various dependency lists with its + usual string representation: relative to the top-level SConstruct + directory, or an absolute path if it's outside. + """ + if os_sep_is_slash: + node_to_str = str + else: + def node_to_str(n): + try: + s = n.get_internal_path() + except AttributeError: + s = str(n) + else: + s = s.replace(OS_SEP, '/') + return s + for attr in ['bsources', 'bdepends', 'bimplicit']: + try: + val = getattr(self, attr) + except AttributeError: + pass + else: + setattr(self, attr, list(map(node_to_str, val))) + + def convert_from_sconsign(self, dir, name): + """ + Converts a newly-read FileBuildInfo object for in-SCons use + + For normal up-to-date checking, we don't have any conversion to + perform--but we're leaving this method here to make that clear. + """ + pass + + def prepare_dependencies(self): + """ + Prepares a FileBuildInfo object for explaining what changed + + The bsources, bdepends and bimplicit lists have all been + stored on disk as paths relative to the top-level SConstruct + directory. Convert the strings to actual Nodes (for use by the + --debug=explain code and --implicit-cache). + """ + attrs = [ + ('bsources', 'bsourcesigs'), + ('bdepends', 'bdependsigs'), + ('bimplicit', 'bimplicitsigs'), + ] + for (nattr, sattr) in attrs: + try: + strings = getattr(self, nattr) + nodeinfos = getattr(self, sattr) + except AttributeError: + continue + if strings is None or nodeinfos is None: + continue + nodes = [] + for s, ni in zip(strings, nodeinfos): + if not isinstance(s, SCons.Node.Node): + s = ni.str_to_node(s) + nodes.append(s) + setattr(self, nattr, nodes) + + def format(self, names=0): + result = [] + bkids = self.bsources + self.bdepends + self.bimplicit + bkidsigs = self.bsourcesigs + self.bdependsigs + self.bimplicitsigs + for bkid, bkidsig in zip(bkids, bkidsigs): + result.append(str(bkid) + ': ' + + ' '.join(bkidsig.format(names=names))) + if not hasattr(self,'bact'): + self.bact = "none" + result.append('%s [%s]' % (self.bactsig, self.bact)) + return '\n'.join(result) + + +class File(Base): + """A class for files in a file system. + """ + + __slots__ = ['scanner_paths', + 'cachedir_csig', + 'cachesig', + 'repositories', + 'srcdir', + 'entries', + 'searched', + '_sconsign', + 'variant_dirs', + 'root', + 'dirname', + 'on_disk_entries', + 'released_target_info', + 'contentsig'] + + NodeInfo = FileNodeInfo + BuildInfo = FileBuildInfo + + md5_chunksize = 64 + + def diskcheck_match(self): + diskcheck_match(self, self.isdir, + "Directory %s found where file expected.") + + def __init__(self, name, directory, fs): + if SCons.Debug.track_instances: logInstanceCreation(self, 'Node.FS.File') + Base.__init__(self, name, directory, fs) + self._morph() + + def Entry(self, name): + """Create an entry node named 'name' relative to + the directory of this file.""" + return self.dir.Entry(name) + + def Dir(self, name, create=True): + """Create a directory node named 'name' relative to + the directory of this file.""" + return self.dir.Dir(name, create=create) + + def Dirs(self, pathlist): + """Create a list of directories relative to the SConscript + directory of this file.""" + return [self.Dir(p) for p in pathlist] + + def File(self, name): + """Create a file node named 'name' relative to + the directory of this file.""" + return self.dir.File(name) + + def _morph(self): + """Turn a file system node into a File object.""" + self.scanner_paths = {} + if not hasattr(self, '_local'): + self._local = 0 + if not hasattr(self, 'released_target_info'): + self.released_target_info = False + + self.store_info = 1 + self._func_exists = 4 + self._func_get_contents = 3 + + # Initialize this Node's decider function to decide_source() because + # every file is a source file until it has a Builder attached... + self.changed_since_last_build = 4 + + # If there was already a Builder set on this entry, then + # we need to make sure we call the target-decider function, + # not the source-decider. Reaching in and doing this by hand + # is a little bogus. We'd prefer to handle this by adding + # an Entry.builder_set() method that disambiguates like the + # other methods, but that starts running into problems with the + # fragile way we initialize Dir Nodes with their Mkdir builders, + # yet still allow them to be overridden by the user. Since it's + # not clear right now how to fix that, stick with what works + # until it becomes clear... + if self.has_builder(): + self.changed_since_last_build = 5 + + def scanner_key(self): + return self.get_suffix() + + def get_contents(self): + return SCons.Node._get_contents_map[self._func_get_contents](self) + + def get_text_contents(self): + """ + This attempts to figure out what the encoding of the text is + based upon the BOM bytes, and then decodes the contents so that + it's a valid python string. + """ + contents = self.get_contents() + # The behavior of various decode() methods and functions + # w.r.t. the initial BOM bytes is different for different + # encodings and/or Python versions. ('utf-8' does not strip + # them, but has a 'utf-8-sig' which does; 'utf-16' seems to + # strip them; etc.) Just sidestep all the complication by + # explicitly stripping the BOM before we decode(). + if contents[:len(codecs.BOM_UTF8)] == codecs.BOM_UTF8: + return contents[len(codecs.BOM_UTF8):].decode('utf-8') + if contents[:len(codecs.BOM_UTF16_LE)] == codecs.BOM_UTF16_LE: + return contents[len(codecs.BOM_UTF16_LE):].decode('utf-16-le') + if contents[:len(codecs.BOM_UTF16_BE)] == codecs.BOM_UTF16_BE: + return contents[len(codecs.BOM_UTF16_BE):].decode('utf-16-be') + try: + return contents.decode('utf-8') + except UnicodeDecodeError as e: + try: + return contents.decode('latin-1') + except UnicodeDecodeError as e: + return contents.decode('utf-8', error='backslashreplace') + + + def get_content_hash(self): + """ + Compute and return the MD5 hash for this file. + """ + if not self.rexists(): + return SCons.Util.MD5signature('') + fname = self.rfile().get_abspath() + try: + cs = SCons.Util.MD5filesignature(fname, + chunksize=SCons.Node.FS.File.md5_chunksize*1024) + except EnvironmentError as e: + if not e.filename: + e.filename = fname + raise + return cs + + @SCons.Memoize.CountMethodCall + def get_size(self): + try: + return self._memo['get_size'] + except KeyError: + pass + + if self.rexists(): + size = self.rfile().getsize() + else: + size = 0 + + self._memo['get_size'] = size + + return size + + @SCons.Memoize.CountMethodCall + def get_timestamp(self): + try: + return self._memo['get_timestamp'] + except KeyError: + pass + + if self.rexists(): + timestamp = self.rfile().getmtime() + else: + timestamp = 0 + + self._memo['get_timestamp'] = timestamp + + return timestamp + + convert_copy_attrs = [ + 'bsources', + 'bimplicit', + 'bdepends', + 'bact', + 'bactsig', + 'ninfo', + ] + + + convert_sig_attrs = [ + 'bsourcesigs', + 'bimplicitsigs', + 'bdependsigs', + ] + + def convert_old_entry(self, old_entry): + # Convert a .sconsign entry from before the Big Signature + # Refactoring, doing what we can to convert its information + # to the new .sconsign entry format. + # + # The old format looked essentially like this: + # + # BuildInfo + # .ninfo (NodeInfo) + # .bsig + # .csig + # .timestamp + # .size + # .bsources + # .bsourcesigs ("signature" list) + # .bdepends + # .bdependsigs ("signature" list) + # .bimplicit + # .bimplicitsigs ("signature" list) + # .bact + # .bactsig + # + # The new format looks like this: + # + # .ninfo (NodeInfo) + # .bsig + # .csig + # .timestamp + # .size + # .binfo (BuildInfo) + # .bsources + # .bsourcesigs (NodeInfo list) + # .bsig + # .csig + # .timestamp + # .size + # .bdepends + # .bdependsigs (NodeInfo list) + # .bsig + # .csig + # .timestamp + # .size + # .bimplicit + # .bimplicitsigs (NodeInfo list) + # .bsig + # .csig + # .timestamp + # .size + # .bact + # .bactsig + # + # The basic idea of the new structure is that a NodeInfo always + # holds all available information about the state of a given Node + # at a certain point in time. The various .b*sigs lists can just + # be a list of pointers to the .ninfo attributes of the different + # dependent nodes, without any copying of information until it's + # time to pickle it for writing out to a .sconsign file. + # + # The complicating issue is that the *old* format only stored one + # "signature" per dependency, based on however the *last* build + # was configured. We don't know from just looking at it whether + # it was a build signature, a content signature, or a timestamp + # "signature". Since we no longer use build signatures, the + # best we can do is look at the length and if it's thirty two, + # assume that it was (or might have been) a content signature. + # If it was actually a build signature, then it will cause a + # rebuild anyway when it doesn't match the new content signature, + # but that's probably the best we can do. + import SCons.SConsign + new_entry = SCons.SConsign.SConsignEntry() + new_entry.binfo = self.new_binfo() + binfo = new_entry.binfo + for attr in self.convert_copy_attrs: + try: + value = getattr(old_entry, attr) + except AttributeError: + continue + setattr(binfo, attr, value) + delattr(old_entry, attr) + for attr in self.convert_sig_attrs: + try: + sig_list = getattr(old_entry, attr) + except AttributeError: + continue + value = [] + for sig in sig_list: + ninfo = self.new_ninfo() + if len(sig) == 32: + ninfo.csig = sig + else: + ninfo.timestamp = sig + value.append(ninfo) + setattr(binfo, attr, value) + delattr(old_entry, attr) + return new_entry + + @SCons.Memoize.CountMethodCall + def get_stored_info(self): + try: + return self._memo['get_stored_info'] + except KeyError: + pass + + try: + sconsign_entry = self.dir.sconsign().get_entry(self.name) + except (KeyError, EnvironmentError): + import SCons.SConsign + sconsign_entry = SCons.SConsign.SConsignEntry() + sconsign_entry.binfo = self.new_binfo() + sconsign_entry.ninfo = self.new_ninfo() + else: + if isinstance(sconsign_entry, FileBuildInfo): + # This is a .sconsign file from before the Big Signature + # Refactoring; convert it as best we can. + sconsign_entry = self.convert_old_entry(sconsign_entry) + try: + delattr(sconsign_entry.ninfo, 'bsig') + except AttributeError: + pass + + self._memo['get_stored_info'] = sconsign_entry + + return sconsign_entry + + def get_stored_implicit(self): + binfo = self.get_stored_info().binfo + binfo.prepare_dependencies() + try: return binfo.bimplicit + except AttributeError: return None + + def rel_path(self, other): + return self.dir.rel_path(other) + + def _get_found_includes_key(self, env, scanner, path): + return (id(env), id(scanner), path) + + @SCons.Memoize.CountDictCall(_get_found_includes_key) + def get_found_includes(self, env, scanner, path): + """Return the included implicit dependencies in this file. + Cache results so we only scan the file once per path + regardless of how many times this information is requested. + """ + memo_key = (id(env), id(scanner), path) + try: + memo_dict = self._memo['get_found_includes'] + except KeyError: + memo_dict = {} + self._memo['get_found_includes'] = memo_dict + else: + try: + return memo_dict[memo_key] + except KeyError: + pass + + if scanner: + result = [n.disambiguate() for n in scanner(self, env, path)] + else: + result = [] + + memo_dict[memo_key] = result + + return result + + def _createDir(self): + # ensure that the directories for this node are + # created. + self.dir._create() + + def push_to_cache(self): + """Try to push the node into a cache + """ + # This should get called before the Nodes' .built() method is + # called, which would clear the build signature if the file has + # a source scanner. + # + # We have to clear the local memoized values *before* we push + # the node to cache so that the memoization of the self.exists() + # return value doesn't interfere. + if self.nocache: + return + self.clear_memoized_values() + if self.exists(): + self.get_build_env().get_CacheDir().push(self) + + def retrieve_from_cache(self): + """Try to retrieve the node's content from a cache + + This method is called from multiple threads in a parallel build, + so only do thread safe stuff here. Do thread unsafe stuff in + built(). + + Returns true if the node was successfully retrieved. + """ + if self.nocache: + return None + if not self.is_derived(): + return None + return self.get_build_env().get_CacheDir().retrieve(self) + + def visited(self): + if self.exists() and self.executor is not None: + self.get_build_env().get_CacheDir().push_if_forced(self) + + ninfo = self.get_ninfo() + + csig = self.get_max_drift_csig() + if csig: + ninfo.csig = csig + + ninfo.timestamp = self.get_timestamp() + ninfo.size = self.get_size() + + if not self.has_builder(): + # This is a source file, but it might have been a target file + # in another build that included more of the DAG. Copy + # any build information that's stored in the .sconsign file + # into our binfo object so it doesn't get lost. + old = self.get_stored_info() + self.get_binfo().merge(old.binfo) + + SCons.Node.store_info_map[self.store_info](self) + + def release_target_info(self): + """Called just after this node has been marked + up-to-date or was built completely. + + This is where we try to release as many target node infos + as possible for clean builds and update runs, in order + to minimize the overall memory consumption. + + We'd like to remove a lot more attributes like self.sources + and self.sources_set, but they might get used + in a next build step. For example, during configuration + the source files for a built E{*}.o file are used to figure out + which linker to use for the resulting Program (gcc vs. g++)! + That's why we check for the 'keep_targetinfo' attribute, + config Nodes and the Interactive mode just don't allow + an early release of most variables. + + In the same manner, we can't simply remove the self.attributes + here. The smart linking relies on the shared flag, and some + parts of the java Tool use it to transport information + about nodes... + + @see: built() and Node.release_target_info() + """ + if (self.released_target_info or SCons.Node.interactive): + return + + if not hasattr(self.attributes, 'keep_targetinfo'): + # Cache some required values, before releasing + # stuff like env, executor and builder... + self.changed(allowcache=True) + self.get_contents_sig() + self.get_build_env() + # Now purge unneeded stuff to free memory... + self.executor = None + self._memo.pop('rfile', None) + self.prerequisites = None + # Cleanup lists, but only if they're empty + if not len(self.ignore_set): + self.ignore_set = None + if not len(self.implicit_set): + self.implicit_set = None + if not len(self.depends_set): + self.depends_set = None + if not len(self.ignore): + self.ignore = None + if not len(self.depends): + self.depends = None + # Mark this node as done, we only have to release + # the memory once... + self.released_target_info = True + + def find_src_builder(self): + if self.rexists(): + return None + scb = self.dir.src_builder() + if scb is _null: + scb = None + if scb is not None: + try: + b = self.builder + except AttributeError: + b = None + if b is None: + self.builder_set(scb) + return scb + + def has_src_builder(self): + """Return whether this Node has a source builder or not. + + If this Node doesn't have an explicit source code builder, this + is where we figure out, on the fly, if there's a transparent + source code builder for it. + + Note that if we found a source builder, we also set the + self.builder attribute, so that all of the methods that actually + *build* this file don't have to do anything different. + """ + try: + scb = self.sbuilder + except AttributeError: + scb = self.sbuilder = self.find_src_builder() + return scb is not None + + def alter_targets(self): + """Return any corresponding targets in a variant directory. + """ + if self.is_derived(): + return [], None + return self.fs.variant_dir_target_climb(self, self.dir, [self.name]) + + def _rmv_existing(self): + self.clear_memoized_values() + if SCons.Node.print_duplicate: + print("dup: removing existing target {}".format(self)) + e = Unlink(self, [], None) + if isinstance(e, SCons.Errors.BuildError): + raise e + + # + # Taskmaster interface subsystem + # + + def make_ready(self): + self.has_src_builder() + self.get_binfo() + + def prepare(self): + """Prepare for this file to be created.""" + SCons.Node.Node.prepare(self) + + if self.get_state() != SCons.Node.up_to_date: + if self.exists(): + if self.is_derived() and not self.precious: + self._rmv_existing() + else: + try: + self._createDir() + except SCons.Errors.StopError as drive: + raise SCons.Errors.StopError("No drive `{}' for target `{}'.".format(drive, self)) + + # + # + # + + def remove(self): + """Remove this file.""" + if self.exists() or self.islink(): + self.fs.unlink(self.get_internal_path()) + return 1 + return None + + def do_duplicate(self, src): + self._createDir() + if SCons.Node.print_duplicate: + print("dup: relinking variant '{}' from '{}'".format(self, src)) + Unlink(self, None, None) + e = Link(self, src, None) + if isinstance(e, SCons.Errors.BuildError): + raise SCons.Errors.StopError("Cannot duplicate `{}' in `{}': {}.".format(src.get_internal_path(), self.dir._path, e.errstr)) + self.linked = 1 + # The Link() action may or may not have actually + # created the file, depending on whether the -n + # option was used or not. Delete the _exists and + # _rexists attributes so they can be reevaluated. + self.clear() + + @SCons.Memoize.CountMethodCall + def exists(self): + try: + return self._memo['exists'] + except KeyError: + pass + result = SCons.Node._exists_map[self._func_exists](self) + self._memo['exists'] = result + return result + + # + # SIGNATURE SUBSYSTEM + # + + def get_max_drift_csig(self): + """ + Returns the content signature currently stored for this node + if it's been unmodified longer than the max_drift value, or the + max_drift value is 0. Returns None otherwise. + """ + old = self.get_stored_info() + mtime = self.get_timestamp() + + max_drift = self.fs.max_drift + if max_drift > 0: + if (time.time() - mtime) > max_drift: + try: + n = old.ninfo + if n.timestamp and n.csig and n.timestamp == mtime: + return n.csig + except AttributeError: + pass + elif max_drift == 0: + try: + return old.ninfo.csig + except AttributeError: + pass + + return None + + def get_csig(self): + """ + Generate a node's content signature, the digested signature + of its content. + + node - the node + cache - alternate node to use for the signature cache + returns - the content signature + """ + ninfo = self.get_ninfo() + try: + return ninfo.csig + except AttributeError: + pass + + csig = self.get_max_drift_csig() + if csig is None: + + try: + if self.get_size() < SCons.Node.FS.File.md5_chunksize: + contents = self.get_contents() + else: + csig = self.get_content_hash() + except IOError: + # This can happen if there's actually a directory on-disk, + # which can be the case if they've disabled disk checks, + # or if an action with a File target actually happens to + # create a same-named directory by mistake. + csig = '' + else: + if not csig: + csig = SCons.Util.MD5signature(contents) + + ninfo.csig = csig + + return csig + + # + # DECISION SUBSYSTEM + # + + def builder_set(self, builder): + SCons.Node.Node.builder_set(self, builder) + self.changed_since_last_build = 5 + + def built(self): + """Called just after this File node is successfully built. + + Just like for 'release_target_info' we try to release + some more target node attributes in order to minimize the + overall memory consumption. + + @see: release_target_info + """ + + SCons.Node.Node.built(self) + + if (not SCons.Node.interactive and + not hasattr(self.attributes, 'keep_targetinfo')): + # Ensure that the build infos get computed and cached... + SCons.Node.store_info_map[self.store_info](self) + # ... then release some more variables. + self._specific_sources = False + self._labspath = None + self._save_str() + self.cwd = None + + self.scanner_paths = None + + def changed(self, node=None, allowcache=False): + """ + Returns if the node is up-to-date with respect to the BuildInfo + stored last time it was built. + + For File nodes this is basically a wrapper around Node.changed(), + but we allow the return value to get cached after the reference + to the Executor got released in release_target_info(). + + @see: Node.changed() + """ + if node is None: + try: + return self._memo['changed'] + except KeyError: + pass + + has_changed = SCons.Node.Node.changed(self, node) + if allowcache: + self._memo['changed'] = has_changed + return has_changed + + def changed_content(self, target, prev_ni): + cur_csig = self.get_csig() + try: + return cur_csig != prev_ni.csig + except AttributeError: + return 1 + + def changed_state(self, target, prev_ni): + return self.state != SCons.Node.up_to_date + + + # Caching node -> string mapping for the below method + __dmap_cache = {} + __dmap_sig_cache = {} + + + def _build_dependency_map(self, binfo): + """ + Build mapping from file -> signature + + Args: + self - self + binfo - buildinfo from node being considered + + Returns: + dictionary of file->signature mappings + """ + + # For an "empty" binfo properties like bsources + # do not exist: check this to avoid exception. + if (len(binfo.bsourcesigs) + len(binfo.bdependsigs) + \ + len(binfo.bimplicitsigs)) == 0: + return {} + + + # store this info so we can avoid regenerating it. + binfo.dependency_map = { str(child):signature for child, signature in zip(chain(binfo.bsources, binfo.bdepends, binfo.bimplicit), + chain(binfo.bsourcesigs, binfo.bdependsigs, binfo.bimplicitsigs))} + + return binfo.dependency_map + + def _get_previous_signatures(self, dmap): + """ + Return a list of corresponding csigs from previous + build in order of the node/files in children. + + Args: + self - self + dmap - Dictionary of file -> csig + + Returns: + List of csigs for provided list of children + """ + prev = [] + # MD5_TIMESTAMP_DEBUG = False + + if len(dmap) == 0: + if MD5_TIMESTAMP_DEBUG: print("Nothing dmap shortcutting") + return None + + if MD5_TIMESTAMP_DEBUG: print("len(dmap):%d"%len(dmap)) + # First try the simple name for node + c_str = str(self) + if MD5_TIMESTAMP_DEBUG: print("Checking :%s"%c_str) + df = dmap.get(c_str, None) + if df: + return df + + if os.altsep: + c_str = c_str.replace(os.sep, os.altsep) + df = dmap.get(c_str, None) + if MD5_TIMESTAMP_DEBUG: print("-->%s"%df) + if df: + return df + + if not df: + try: + # this should yield a path which matches what's in the sconsign + c_str = self.get_path() + df = dmap.get(c_str, None) + if MD5_TIMESTAMP_DEBUG: print("-->%s"%df) + if df: + return df + + if os.altsep: + c_str = c_str.replace(os.sep, os.altsep) + df = dmap.get(c_str, None) + if MD5_TIMESTAMP_DEBUG: print("-->%s"%df) + if df: + return df + + except AttributeError as e: + raise FileBuildInfoFileToCsigMappingError("No mapping from file name to content signature for :%s"%c_str) + + return df + + def changed_timestamp_then_content(self, target, prev_ni, node=None): + """ + Used when decider for file is Timestamp-MD5 + + NOTE: If the timestamp hasn't changed this will skip md5'ing the + file and just copy the prev_ni provided. If the prev_ni + is wrong. It will propagate it. + See: https://github.com/SCons/scons/issues/2980 + + Args: + self - dependency + target - target + prev_ni - The NodeInfo object loaded from previous builds .sconsign + node - Node instance. This is the only changed* function which requires + node to function. So if we detect that it's not passed. + we throw DeciderNeedsNode, and caller should handle this and pass node. + + Returns: + Boolean - Indicates if node(File) has changed. + """ + if node is None: + # We need required node argument to get BuildInfo to function + raise DeciderNeedsNode(self.changed_timestamp_then_content) + + # Now get sconsign name -> csig map and then get proper prev_ni if possible + bi = node.get_stored_info().binfo + rebuilt = False + try: + dependency_map = bi.dependency_map + except AttributeError as e: + dependency_map = self._build_dependency_map(bi) + rebuilt = True + + if len(dependency_map) == 0: + # If there's no dependency map, there's no need to find the + # prev_ni as there aren't any + # shortcut the rest of the logic + if MD5_TIMESTAMP_DEBUG: print("Skipping checks len(dmap)=0") + + # We still need to get the current file's csig + # This should be slightly faster than calling self.changed_content(target, new_prev_ni) + self.get_csig() + return True + + new_prev_ni = self._get_previous_signatures(dependency_map) + new = self.changed_timestamp_match(target, new_prev_ni) + + if MD5_TIMESTAMP_DEBUG: + old = self.changed_timestamp_match(target, prev_ni) + + if old != new: + print("Mismatch self.changed_timestamp_match(%s, prev_ni) old:%s new:%s"%(str(target), old, new)) + new_prev_ni = self._get_previous_signatures(dependency_map) + + + if not new: + try: + # NOTE: We're modifying the current node's csig in a query. + self.get_ninfo().csig = new_prev_ni.csig + except AttributeError: + pass + return False + return self.changed_content(target, new_prev_ni) + + def changed_timestamp_newer(self, target, prev_ni): + try: + return self.get_timestamp() > target.get_timestamp() + except AttributeError: + return 1 + + def changed_timestamp_match(self, target, prev_ni): + """ + Return True if the timestamps don't match or if there is no previous timestamp + :param target: + :param prev_ni: Information about the node from the previous build + :return: + """ + try: + return self.get_timestamp() != prev_ni.timestamp + except AttributeError: + return 1 + + def is_up_to_date(self): + T = 0 + if T: Trace('is_up_to_date(%s):' % self) + if not self.exists(): + if T: Trace(' not self.exists():') + # The file doesn't exist locally... + r = self.rfile() + if r != self: + # ...but there is one in a Repository... + if not self.changed(r): + if T: Trace(' changed(%s):' % r) + # ...and it's even up-to-date... + if self._local: + # ...and they'd like a local copy. + e = LocalCopy(self, r, None) + if isinstance(e, SCons.Errors.BuildError): + # Likely this should be re-raising exception e + # (which would be BuildError) + raise e + SCons.Node.store_info_map[self.store_info](self) + if T: Trace(' 1\n') + return 1 + self.changed() + if T: Trace(' None\n') + return None + else: + r = self.changed() + if T: Trace(' self.exists(): %s\n' % r) + return not r + + @SCons.Memoize.CountMethodCall + def rfile(self): + try: + return self._memo['rfile'] + except KeyError: + pass + result = self + if not self.exists(): + norm_name = _my_normcase(self.name) + for repo_dir in self.dir.get_all_rdirs(): + try: + node = repo_dir.entries[norm_name] + except KeyError: + node = repo_dir.file_on_disk(self.name) + + if node and node.exists() and \ + (isinstance(node, File) or isinstance(node, Entry) + or not node.is_derived()): + result = node + # Copy over our local attributes to the repository + # Node so we identify shared object files in the + # repository and don't assume they're static. + # + # This isn't perfect; the attribute would ideally + # be attached to the object in the repository in + # case it was built statically in the repository + # and we changed it to shared locally, but that's + # rarely the case and would only occur if you + # intentionally used the same suffix for both + # shared and static objects anyway. So this + # should work well in practice. + result.attributes = self.attributes + break + self._memo['rfile'] = result + return result + + def find_repo_file(self): + """ + For this node, find if there exists a corresponding file in one or more repositories + :return: list of corresponding files in repositories + """ + retvals = [] + + norm_name = _my_normcase(self.name) + for repo_dir in self.dir.get_all_rdirs(): + try: + node = repo_dir.entries[norm_name] + except KeyError: + node = repo_dir.file_on_disk(self.name) + + if node and node.exists() and \ + (isinstance(node, File) or isinstance(node, Entry) \ + or not node.is_derived()): + retvals.append(node) + + return retvals + + + def rstr(self): + return str(self.rfile()) + + def get_cachedir_csig(self): + """ + Fetch a Node's content signature for purposes of computing + another Node's cachesig. + + This is a wrapper around the normal get_csig() method that handles + the somewhat obscure case of using CacheDir with the -n option. + Any files that don't exist would normally be "built" by fetching + them from the cache, but the normal get_csig() method will try + to open up the local file, which doesn't exist because the -n + option meant we didn't actually pull the file from cachedir. + But since the file *does* actually exist in the cachedir, we + can use its contents for the csig. + """ + try: + return self.cachedir_csig + except AttributeError: + pass + + cachedir, cachefile = self.get_build_env().get_CacheDir().cachepath(self) + if not self.exists() and cachefile and os.path.exists(cachefile): + self.cachedir_csig = SCons.Util.MD5filesignature(cachefile, \ + SCons.Node.FS.File.md5_chunksize * 1024) + else: + self.cachedir_csig = self.get_csig() + return self.cachedir_csig + + def get_contents_sig(self): + """ + A helper method for get_cachedir_bsig. + + It computes and returns the signature for this + node's contents. + """ + + try: + return self.contentsig + except AttributeError: + pass + + executor = self.get_executor() + + result = self.contentsig = SCons.Util.MD5signature(executor.get_contents()) + return result + + def get_cachedir_bsig(self): + """ + Return the signature for a cached file, including + its children. + + It adds the path of the cached file to the cache signature, + because multiple targets built by the same action will all + have the same build signature, and we have to differentiate + them somehow. + + Signature should normally be string of hex digits. + """ + try: + return self.cachesig + except AttributeError: + pass + + # Collect signatures for all children + children = self.children() + sigs = [n.get_cachedir_csig() for n in children] + + # Append this node's signature... + sigs.append(self.get_contents_sig()) + + # ...and it's path + sigs.append(self.get_internal_path()) + + # Merge this all into a single signature + result = self.cachesig = SCons.Util.MD5collect(sigs) + return result + +default_fs = None + +def get_default_fs(): + global default_fs + if not default_fs: + default_fs = FS() + return default_fs + +class FileFinder(object): + """ + """ + + def __init__(self): + self._memo = {} + + def filedir_lookup(self, p, fd=None): + """ + A helper method for find_file() that looks up a directory for + a file we're trying to find. This only creates the Dir Node if + it exists on-disk, since if the directory doesn't exist we know + we won't find any files in it... :-) + + It would be more compact to just use this as a nested function + with a default keyword argument (see the commented-out version + below), but that doesn't work unless you have nested scopes, + so we define it here just so this work under Python 1.5.2. + """ + if fd is None: + fd = self.default_filedir + dir, name = os.path.split(fd) + drive, d = _my_splitdrive(dir) + if not name and d[:1] in ('/', OS_SEP): + #return p.fs.get_root(drive).dir_on_disk(name) + return p.fs.get_root(drive) + if dir: + p = self.filedir_lookup(p, dir) + if not p: + return None + norm_name = _my_normcase(name) + try: + node = p.entries[norm_name] + except KeyError: + return p.dir_on_disk(name) + if isinstance(node, Dir): + return node + if isinstance(node, Entry): + node.must_be_same(Dir) + return node + return None + + def _find_file_key(self, filename, paths, verbose=None): + return (filename, paths) + + @SCons.Memoize.CountDictCall(_find_file_key) + def find_file(self, filename, paths, verbose=None): + """ + Find a node corresponding to either a derived file or a file that exists already. + + Only the first file found is returned, and none is returned if no file is found. + + filename: A filename to find + paths: A list of directory path *nodes* to search in. Can be represented as a list, a tuple, or a callable that is called with no arguments and returns the list or tuple. + + returns The node created from the found file. + + """ + memo_key = self._find_file_key(filename, paths) + try: + memo_dict = self._memo['find_file'] + except KeyError: + memo_dict = {} + self._memo['find_file'] = memo_dict + else: + try: + return memo_dict[memo_key] + except KeyError: + pass + + if verbose and not callable(verbose): + if not SCons.Util.is_String(verbose): + verbose = "find_file" + _verbose = u' %s: ' % verbose + verbose = lambda s: sys.stdout.write(_verbose + s) + + filedir, filename = os.path.split(filename) + if filedir: + self.default_filedir = filedir + paths = [_f for _f in map(self.filedir_lookup, paths) if _f] + + result = None + for dir in paths: + if verbose: + verbose("looking for '%s' in '%s' ...\n" % (filename, dir)) + node, d = dir.srcdir_find_file(filename) + if node: + if verbose: + verbose("... FOUND '%s' in '%s'\n" % (filename, d)) + result = node + break + + memo_dict[memo_key] = result + + return result + +find_file = FileFinder().find_file + + +def invalidate_node_memos(targets): + """ + Invalidate the memoized values of all Nodes (files or directories) + that are associated with the given entries. Has been added to + clear the cache of nodes affected by a direct execution of an + action (e.g. Delete/Copy/Chmod). Existing Node caches become + inconsistent if the action is run through Execute(). The argument + `targets` can be a single Node object or filename, or a sequence + of Nodes/filenames. + """ + from traceback import extract_stack + + # First check if the cache really needs to be flushed. Only + # actions run in the SConscript with Execute() seem to be + # affected. XXX The way to check if Execute() is in the stacktrace + # is a very dirty hack and should be replaced by a more sensible + # solution. + for f in extract_stack(): + if f[2] == 'Execute' and f[0][-14:] == 'Environment.py': + break + else: + # Dont have to invalidate, so return + return + + if not SCons.Util.is_List(targets): + targets = [targets] + + for entry in targets: + # If the target is a Node object, clear the cache. If it is a + # filename, look up potentially existing Node object first. + try: + entry.clear_memoized_values() + except AttributeError: + # Not a Node object, try to look up Node by filename. XXX + # This creates Node objects even for those filenames which + # do not correspond to an existing Node object. + node = get_default_fs().Entry(entry) + if node: + node.clear_memoized_values() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Node/Python.py b/tools/scons/scons-local-3.0.5/SCons/Node/Python.py new file mode 100755 index 0000000000..d235de8913 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Node/Python.py @@ -0,0 +1,180 @@ +"""scons.Node.Python + +Python nodes. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Node/Python.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Node + +class ValueNodeInfo(SCons.Node.NodeInfoBase): + __slots__ = ('csig',) + current_version_id = 2 + + field_list = ['csig'] + + def str_to_node(self, s): + return Value(s) + + def __getstate__(self): + """ + Return all fields that shall be pickled. Walk the slots in the class + hierarchy and add those to the state dictionary. If a '__dict__' slot is + available, copy all entries to the dictionary. Also include the version + id, which is fixed for all instances of a class. + """ + state = getattr(self, '__dict__', {}).copy() + for obj in type(self).mro(): + for name in getattr(obj,'__slots__',()): + if hasattr(self, name): + state[name] = getattr(self, name) + + state['_version_id'] = self.current_version_id + try: + del state['__weakref__'] + except KeyError: + pass + + return state + + def __setstate__(self, state): + """ + Restore the attributes from a pickled state. + """ + # TODO check or discard version + del state['_version_id'] + for key, value in state.items(): + if key not in ('__weakref__',): + setattr(self, key, value) + + +class ValueBuildInfo(SCons.Node.BuildInfoBase): + __slots__ = () + current_version_id = 2 + +class Value(SCons.Node.Node): + """A class for Python variables, typically passed on the command line + or generated by a script, but not from a file or some other source. + """ + + NodeInfo = ValueNodeInfo + BuildInfo = ValueBuildInfo + + def __init__(self, value, built_value=None): + SCons.Node.Node.__init__(self) + self.value = value + self.changed_since_last_build = 6 + self.store_info = 0 + if built_value is not None: + self.built_value = built_value + + def str_for_display(self): + return repr(self.value) + + def __str__(self): + return str(self.value) + + def make_ready(self): + self.get_csig() + + def build(self, **kw): + if not hasattr(self, 'built_value'): + SCons.Node.Node.build(self, **kw) + + is_up_to_date = SCons.Node.Node.children_are_up_to_date + + def is_under(self, dir): + # Make Value nodes get built regardless of + # what directory scons was run from. Value nodes + # are outside the filesystem: + return 1 + + def write(self, built_value): + """Set the value of the node.""" + self.built_value = built_value + + def read(self): + """Return the value. If necessary, the value is built.""" + self.build() + if not hasattr(self, 'built_value'): + self.built_value = self.value + return self.built_value + + def get_text_contents(self): + """By the assumption that the node.built_value is a + deterministic product of the sources, the contents of a Value + are the concatenation of all the contents of its sources. As + the value need not be built when get_contents() is called, we + cannot use the actual node.built_value.""" + ###TODO: something reasonable about universal newlines + contents = str(self.value) + for kid in self.children(None): + contents = contents + kid.get_contents().decode() + return contents + + def get_contents(self): + """ + Get contents for signature calculations. + :return: bytes + """ + text_contents = self.get_text_contents() + try: + return text_contents.encode() + except UnicodeDecodeError: + # Already encoded as python2 str are bytes + return text_contents + + + def changed_since_last_build(self, target, prev_ni): + cur_csig = self.get_csig() + try: + return cur_csig != prev_ni.csig + except AttributeError: + return 1 + + def get_csig(self, calc=None): + """Because we're a Python value node and don't have a real + timestamp, we get to ignore the calculator and just use the + value contents. + + Returns string. Ideally string of hex digits. (Not bytes) + """ + try: + return self.ninfo.csig + except AttributeError: + pass + + contents = self.get_text_contents() + + self.get_ninfo().csig = contents + return contents + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Node/__init__.py b/tools/scons/scons-local-3.0.5/SCons/Node/__init__.py new file mode 100755 index 0000000000..889e7a4eed --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Node/__init__.py @@ -0,0 +1,1773 @@ +"""SCons.Node + +The Node package for the SCons software construction utility. + +This is, in many ways, the heart of SCons. + +A Node is where we encapsulate all of the dependency information about +any thing that SCons can build, or about any thing which SCons can use +to build some other thing. The canonical "thing," of course, is a file, +but a Node can also represent something remote (like a web page) or +something completely abstract (like an Alias). + +Each specific type of "thing" is specifically represented by a subclass +of the Node base class: Node.FS.File for files, Node.Alias for aliases, +etc. Dependency information is kept here in the base class, and +information specific to files/aliases/etc. is in the subclass. The +goal, if we've done this correctly, is that any type of "thing" should +be able to depend on any other type of "thing." + +""" + +from __future__ import print_function + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +__revision__ = "src/engine/SCons/Node/__init__.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os +import collections +import copy +from itertools import chain + +import SCons.Debug +from SCons.Debug import logInstanceCreation +import SCons.Executor +import SCons.Memoize +import SCons.Util + +from SCons.Debug import Trace + +from SCons.compat import with_metaclass, NoSlotsPyPy + +print_duplicate = 0 + +def classname(obj): + return str(obj.__class__).split('.')[-1] + +# Set to false if we're doing a dry run. There's more than one of these +# little treats +do_store_info = True + +# Node states +# +# These are in "priority" order, so that the maximum value for any +# child/dependency of a node represents the state of that node if +# it has no builder of its own. The canonical example is a file +# system directory, which is only up to date if all of its children +# were up to date. +no_state = 0 +pending = 1 +executing = 2 +up_to_date = 3 +executed = 4 +failed = 5 + +StateString = { + 0 : "no_state", + 1 : "pending", + 2 : "executing", + 3 : "up_to_date", + 4 : "executed", + 5 : "failed", +} + +# controls whether implicit dependencies are cached: +implicit_cache = 0 + +# controls whether implicit dep changes are ignored: +implicit_deps_unchanged = 0 + +# controls whether the cached implicit deps are ignored: +implicit_deps_changed = 0 + +# A variable that can be set to an interface-specific function be called +# to annotate a Node with information about its creation. +def do_nothing(node): pass + +Annotate = do_nothing + +# Gets set to 'True' if we're running in interactive mode. Is +# currently used to release parts of a target's info during +# clean builds and update runs (see release_target_info). +interactive = False + +def is_derived_none(node): + raise NotImplementedError + +def is_derived_node(node): + """ + Returns true if this node is derived (i.e. built). + """ + return node.has_builder() or node.side_effect + +_is_derived_map = {0 : is_derived_none, + 1 : is_derived_node} + +def exists_none(node): + raise NotImplementedError + +def exists_always(node): + return 1 + +def exists_base(node): + return node.stat() is not None + +def exists_entry(node): + """Return if the Entry exists. Check the file system to see + what we should turn into first. Assume a file if there's no + directory.""" + node.disambiguate() + return _exists_map[node._func_exists](node) + + +def exists_file(node): + # Duplicate from source path if we are set up to do this. + if node.duplicate and not node.is_derived() and not node.linked: + src = node.srcnode() + if src is not node: + # At this point, src is meant to be copied in a variant directory. + src = src.rfile() + if src.get_abspath() != node.get_abspath(): + if src.exists(): + node.do_duplicate(src) + # Can't return 1 here because the duplication might + # not actually occur if the -n option is being used. + else: + # The source file does not exist. Make sure no old + # copy remains in the variant directory. + if print_duplicate: + print("dup: no src for %s, unlinking old variant copy" % node) + if exists_base(node) or node.islink(): + node.fs.unlink(node.get_internal_path()) + # Return None explicitly because the Base.exists() call + # above will have cached its value if the file existed. + return None + return exists_base(node) + +_exists_map = {0 : exists_none, + 1 : exists_always, + 2 : exists_base, + 3 : exists_entry, + 4 : exists_file} + + +def rexists_none(node): + raise NotImplementedError + +def rexists_node(node): + return node.exists() + +def rexists_base(node): + return node.rfile().exists() + +_rexists_map = {0 : rexists_none, + 1 : rexists_node, + 2 : rexists_base} + +def get_contents_none(node): + raise NotImplementedError + +def get_contents_entry(node): + """Fetch the contents of the entry. Returns the exact binary + contents of the file.""" + try: + node = node.disambiguate(must_exist=1) + except SCons.Errors.UserError: + # There was nothing on disk with which to disambiguate + # this entry. Leave it as an Entry, but return a null + # string so calls to get_contents() in emitters and the + # like (e.g. in qt.py) don't have to disambiguate by hand + # or catch the exception. + return '' + else: + return _get_contents_map[node._func_get_contents](node) + +def get_contents_dir(node): + """Return content signatures and names of all our children + separated by new-lines. Ensure that the nodes are sorted.""" + contents = [] + for n in sorted(node.children(), key=lambda t: t.name): + contents.append('%s %s\n' % (n.get_csig(), n.name)) + return ''.join(contents) + +def get_contents_file(node): + if not node.rexists(): + return b'' + fname = node.rfile().get_abspath() + try: + with open(fname, "rb") as fp: + contents = fp.read() + except EnvironmentError as e: + if not e.filename: + e.filename = fname + raise + return contents + +_get_contents_map = {0 : get_contents_none, + 1 : get_contents_entry, + 2 : get_contents_dir, + 3 : get_contents_file} + +def target_from_source_none(node, prefix, suffix, splitext): + raise NotImplementedError + +def target_from_source_base(node, prefix, suffix, splitext): + return node.dir.Entry(prefix + splitext(node.name)[0] + suffix) + +_target_from_source_map = {0 : target_from_source_none, + 1 : target_from_source_base} + +# +# The new decider subsystem for Nodes +# +# We would set and overwrite the changed_since_last_build function +# before, but for being able to use slots (less memory!) we now have +# a dictionary of the different decider functions. Then in the Node +# subclasses we simply store the index to the decider that should be +# used by it. +# + + +class DeciderNeedsNode(Exception): + """ + Indicate that the decider needs the node as well as the target and the dependency. + Normally the node and the target are the same, but in the case of repository + They may be different. Also the NodeInfo is retrieved from the node + """ + def __init__(self, call_this_decider): + """ + :param call_this_decider: to return the decider to call directly since deciders + are called through several levels of indirection + """ + self.decider = call_this_decider + + +# +# First, the single decider functions +# +def changed_since_last_build_node(node, target, prev_ni): + """ + + Must be overridden in a specific subclass to return True if this + Node (a dependency) has changed since the last time it was used + to build the specified target. prev_ni is this Node's state (for + example, its file timestamp, length, maybe content signature) + as of the last time the target was built. + + Note that this method is called through the dependency, not the + target, because a dependency Node must be able to use its own + logic to decide if it changed. For example, File Nodes need to + obey if we're configured to use timestamps, but Python Value Nodes + never use timestamps and always use the content. If this method + were called through the target, then each Node's implementation + of this method would have to have more complicated logic to + handle all the different Node types on which it might depend. + """ + raise NotImplementedError + + +def changed_since_last_build_alias(node, target, prev_ni): + cur_csig = node.get_csig() + try: + return cur_csig != prev_ni.csig + except AttributeError: + return 1 + + +def changed_since_last_build_entry(node, target, prev_ni): + node.disambiguate() + return _decider_map[node.changed_since_last_build](node, target, prev_ni) + + +def changed_since_last_build_state_changed(node, target, prev_ni): + return node.state != SCons.Node.up_to_date + + +def decide_source(node, target, prev_ni): + return target.get_build_env().decide_source(node, target, prev_ni) + + +def decide_target(node, target, prev_ni): + return target.get_build_env().decide_target(node, target, prev_ni) + + +def changed_since_last_build_python(node, target, prev_ni): + cur_csig = node.get_csig() + try: + return cur_csig != prev_ni.csig + except AttributeError: + return 1 + + +# +# Now, the mapping from indices to decider functions +# +_decider_map = {0 : changed_since_last_build_node, + 1 : changed_since_last_build_alias, + 2 : changed_since_last_build_entry, + 3 : changed_since_last_build_state_changed, + 4 : decide_source, + 5 : decide_target, + 6 : changed_since_last_build_python} + +do_store_info = True + +# +# The new store_info subsystem for Nodes +# +# We would set and overwrite the store_info function +# before, but for being able to use slots (less memory!) we now have +# a dictionary of the different functions. Then in the Node +# subclasses we simply store the index to the info method that should be +# used by it. +# + +# +# First, the single info functions +# + +def store_info_pass(node): + pass + +def store_info_file(node): + # Merge our build information into the already-stored entry. + # This accommodates "chained builds" where a file that's a target + # in one build (SConstruct file) is a source in a different build. + # See test/chained-build.py for the use case. + if do_store_info: + node.dir.sconsign().store_info(node.name, node) + + +store_info_map = {0 : store_info_pass, + 1 : store_info_file} + +# Classes for signature info for Nodes. + +class NodeInfoBase(object): + """ + The generic base class for signature information for a Node. + + Node subclasses should subclass NodeInfoBase to provide their own + logic for dealing with their own Node-specific signature information. + """ + __slots__ = ('__weakref__',) + current_version_id = 2 + + def update(self, node): + try: + field_list = self.field_list + except AttributeError: + return + for f in field_list: + try: + delattr(self, f) + except AttributeError: + pass + try: + func = getattr(node, 'get_' + f) + except AttributeError: + pass + else: + setattr(self, f, func()) + + def convert(self, node, val): + pass + + def merge(self, other): + """ + Merge the fields of another object into this object. Already existing + information is overwritten by the other instance's data. + WARNING: If a '__dict__' slot is added, it should be updated instead of + replaced. + """ + state = other.__getstate__() + self.__setstate__(state) + + def format(self, field_list=None, names=0): + if field_list is None: + try: + field_list = self.field_list + except AttributeError: + field_list = list(getattr(self, '__dict__', {}).keys()) + for obj in type(self).mro(): + for slot in getattr(obj, '__slots__', ()): + if slot not in ('__weakref__', '__dict__'): + field_list.append(slot) + field_list.sort() + fields = [] + for field in field_list: + try: + f = getattr(self, field) + except AttributeError: + f = None + f = str(f) + if names: + f = field + ': ' + f + fields.append(f) + return fields + + def __getstate__(self): + """ + Return all fields that shall be pickled. Walk the slots in the class + hierarchy and add those to the state dictionary. If a '__dict__' slot is + available, copy all entries to the dictionary. Also include the version + id, which is fixed for all instances of a class. + """ + state = getattr(self, '__dict__', {}).copy() + for obj in type(self).mro(): + for name in getattr(obj,'__slots__',()): + if hasattr(self, name): + state[name] = getattr(self, name) + + state['_version_id'] = self.current_version_id + try: + del state['__weakref__'] + except KeyError: + pass + return state + + def __setstate__(self, state): + """ + Restore the attributes from a pickled state. The version is discarded. + """ + # TODO check or discard version + del state['_version_id'] + + for key, value in state.items(): + if key not in ('__weakref__',): + setattr(self, key, value) + + +class BuildInfoBase(object): + """ + The generic base class for build information for a Node. + + This is what gets stored in a .sconsign file for each target file. + It contains a NodeInfo instance for this node (signature information + that's specific to the type of Node) and direct attributes for the + generic build stuff we have to track: sources, explicit dependencies, + implicit dependencies, and action information. + """ + __slots__ = ("bsourcesigs", "bdependsigs", "bimplicitsigs", "bactsig", + "bsources", "bdepends", "bact", "bimplicit", "__weakref__") + current_version_id = 2 + + def __init__(self): + # Create an object attribute from the class attribute so it ends up + # in the pickled data in the .sconsign file. + self.bsourcesigs = [] + self.bdependsigs = [] + self.bimplicitsigs = [] + self.bactsig = None + + def merge(self, other): + """ + Merge the fields of another object into this object. Already existing + information is overwritten by the other instance's data. + WARNING: If a '__dict__' slot is added, it should be updated instead of + replaced. + """ + state = other.__getstate__() + self.__setstate__(state) + + def __getstate__(self): + """ + Return all fields that shall be pickled. Walk the slots in the class + hierarchy and add those to the state dictionary. If a '__dict__' slot is + available, copy all entries to the dictionary. Also include the version + id, which is fixed for all instances of a class. + """ + state = getattr(self, '__dict__', {}).copy() + for obj in type(self).mro(): + for name in getattr(obj,'__slots__',()): + if hasattr(self, name): + state[name] = getattr(self, name) + + state['_version_id'] = self.current_version_id + try: + del state['__weakref__'] + except KeyError: + pass + return state + + def __setstate__(self, state): + """ + Restore the attributes from a pickled state. + """ + # TODO check or discard version + del state['_version_id'] + for key, value in state.items(): + if key not in ('__weakref__',): + setattr(self, key, value) + + +class Node(object, with_metaclass(NoSlotsPyPy)): + """The base Node class, for entities that we know how to + build, or use to build other Nodes. + """ + + __slots__ = ['sources', + 'sources_set', + '_specific_sources', + 'depends', + 'depends_set', + 'ignore', + 'ignore_set', + 'prerequisites', + 'implicit', + 'waiting_parents', + 'waiting_s_e', + 'ref_count', + 'wkids', + 'env', + 'state', + 'precious', + 'noclean', + 'nocache', + 'cached', + 'always_build', + 'includes', + 'attributes', + 'side_effect', + 'side_effects', + 'linked', + '_memo', + 'executor', + 'binfo', + 'ninfo', + 'builder', + 'is_explicit', + 'implicit_set', + 'changed_since_last_build', + 'store_info', + 'pseudo', + '_tags', + '_func_is_derived', + '_func_exists', + '_func_rexists', + '_func_get_contents', + '_func_target_from_source'] + + class Attrs(object): + __slots__ = ('shared', '__dict__') + + + def __init__(self): + if SCons.Debug.track_instances: logInstanceCreation(self, 'Node.Node') + # Note that we no longer explicitly initialize a self.builder + # attribute to None here. That's because the self.builder + # attribute may be created on-the-fly later by a subclass (the + # canonical example being a builder to fetch a file from a + # source code system like CVS or Subversion). + + # Each list of children that we maintain is accompanied by a + # dictionary used to look up quickly whether a node is already + # present in the list. Empirical tests showed that it was + # fastest to maintain them as side-by-side Node attributes in + # this way, instead of wrapping up each list+dictionary pair in + # a class. (Of course, we could always still do that in the + # future if we had a good reason to...). + self.sources = [] # source files used to build node + self.sources_set = set() + self._specific_sources = False + self.depends = [] # explicit dependencies (from Depends) + self.depends_set = set() + self.ignore = [] # dependencies to ignore + self.ignore_set = set() + self.prerequisites = None + self.implicit = None # implicit (scanned) dependencies (None means not scanned yet) + self.waiting_parents = set() + self.waiting_s_e = set() + self.ref_count = 0 + self.wkids = None # Kids yet to walk, when it's an array + + self.env = None + self.state = no_state + self.precious = None + self.pseudo = False + self.noclean = 0 + self.nocache = 0 + self.cached = 0 # is this node pulled from cache? + self.always_build = None + self.includes = None + self.attributes = self.Attrs() # Generic place to stick information about the Node. + self.side_effect = 0 # true iff this node is a side effect + self.side_effects = [] # the side effects of building this target + self.linked = 0 # is this node linked to the variant directory? + self.changed_since_last_build = 0 + self.store_info = 0 + self._tags = None + self._func_is_derived = 1 + self._func_exists = 1 + self._func_rexists = 1 + self._func_get_contents = 0 + self._func_target_from_source = 0 + + self.clear_memoized_values() + + # Let the interface in which the build engine is embedded + # annotate this Node with its own info (like a description of + # what line in what file created the node, for example). + Annotate(self) + + def disambiguate(self, must_exist=None): + return self + + def get_suffix(self): + return '' + + @SCons.Memoize.CountMethodCall + def get_build_env(self): + """Fetch the appropriate Environment to build this node. + """ + try: + return self._memo['get_build_env'] + except KeyError: + pass + result = self.get_executor().get_build_env() + self._memo['get_build_env'] = result + return result + + def get_build_scanner_path(self, scanner): + """Fetch the appropriate scanner path for this node.""" + return self.get_executor().get_build_scanner_path(scanner) + + def set_executor(self, executor): + """Set the action executor for this node.""" + self.executor = executor + + def get_executor(self, create=1): + """Fetch the action executor for this node. Create one if + there isn't already one, and requested to do so.""" + try: + executor = self.executor + except AttributeError: + if not create: + raise + try: + act = self.builder.action + except AttributeError: + executor = SCons.Executor.Null(targets=[self]) + else: + executor = SCons.Executor.Executor(act, + self.env or self.builder.env, + [self.builder.overrides], + [self], + self.sources) + self.executor = executor + return executor + + def executor_cleanup(self): + """Let the executor clean up any cached information.""" + try: + executor = self.get_executor(create=None) + except AttributeError: + pass + else: + if executor is not None: + executor.cleanup() + + def reset_executor(self): + """Remove cached executor; forces recompute when needed.""" + try: + delattr(self, 'executor') + except AttributeError: + pass + + def push_to_cache(self): + """Try to push a node into a cache + """ + pass + + def retrieve_from_cache(self): + """Try to retrieve the node's content from a cache + + This method is called from multiple threads in a parallel build, + so only do thread safe stuff here. Do thread unsafe stuff in + built(). + + Returns true if the node was successfully retrieved. + """ + return 0 + + # + # Taskmaster interface subsystem + # + + def make_ready(self): + """Get a Node ready for evaluation. + + This is called before the Taskmaster decides if the Node is + up-to-date or not. Overriding this method allows for a Node + subclass to be disambiguated if necessary, or for an implicit + source builder to be attached. + """ + pass + + def prepare(self): + """Prepare for this Node to be built. + + This is called after the Taskmaster has decided that the Node + is out-of-date and must be rebuilt, but before actually calling + the method to build the Node. + + This default implementation checks that explicit or implicit + dependencies either exist or are derived, and initializes the + BuildInfo structure that will hold the information about how + this node is, uh, built. + + (The existence of source files is checked separately by the + Executor, which aggregates checks for all of the targets built + by a specific action.) + + Overriding this method allows for for a Node subclass to remove + the underlying file from the file system. Note that subclass + methods should call this base class method to get the child + check and the BuildInfo structure. + """ + if self.depends is not None: + for d in self.depends: + if d.missing(): + msg = "Explicit dependency `%s' not found, needed by target `%s'." + raise SCons.Errors.StopError(msg % (d, self)) + if self.implicit is not None: + for i in self.implicit: + if i.missing(): + msg = "Implicit dependency `%s' not found, needed by target `%s'." + raise SCons.Errors.StopError(msg % (i, self)) + self.binfo = self.get_binfo() + + def build(self, **kw): + """Actually build the node. + + This is called by the Taskmaster after it's decided that the + Node is out-of-date and must be rebuilt, and after the prepare() + method has gotten everything, uh, prepared. + + This method is called from multiple threads in a parallel build, + so only do thread safe stuff here. Do thread unsafe stuff + in built(). + + """ + try: + self.get_executor()(self, **kw) + except SCons.Errors.BuildError as e: + e.node = self + raise + + def built(self): + """Called just after this node is successfully built.""" + + # Clear the implicit dependency caches of any Nodes + # waiting for this Node to be built. + for parent in self.waiting_parents: + parent.implicit = None + + self.clear() + + if self.pseudo: + if self.exists(): + raise SCons.Errors.UserError("Pseudo target " + str(self) + " must not exist") + else: + if not self.exists() and do_store_info: + SCons.Warnings.warn(SCons.Warnings.TargetNotBuiltWarning, + "Cannot find target " + str(self) + " after building") + self.ninfo.update(self) + + def visited(self): + """Called just after this node has been visited (with or + without a build).""" + try: + binfo = self.binfo + except AttributeError: + # Apparently this node doesn't need build info, so + # don't bother calculating or storing it. + pass + else: + self.ninfo.update(self) + SCons.Node.store_info_map[self.store_info](self) + + def release_target_info(self): + """Called just after this node has been marked + up-to-date or was built completely. + + This is where we try to release as many target node infos + as possible for clean builds and update runs, in order + to minimize the overall memory consumption. + + By purging attributes that aren't needed any longer after + a Node (=File) got built, we don't have to care that much how + many KBytes a Node actually requires...as long as we free + the memory shortly afterwards. + + @see: built() and File.release_target_info() + """ + pass + + # + # + # + + def add_to_waiting_s_e(self, node): + self.waiting_s_e.add(node) + + def add_to_waiting_parents(self, node): + """ + Returns the number of nodes added to our waiting parents list: + 1 if we add a unique waiting parent, 0 if not. (Note that the + returned values are intended to be used to increment a reference + count, so don't think you can "clean up" this function by using + True and False instead...) + """ + wp = self.waiting_parents + if node in wp: + return 0 + wp.add(node) + return 1 + + def postprocess(self): + """Clean up anything we don't need to hang onto after we've + been built.""" + self.executor_cleanup() + self.waiting_parents = set() + + def clear(self): + """Completely clear a Node of all its cached state (so that it + can be re-evaluated by interfaces that do continuous integration + builds). + """ + # The del_binfo() call here isn't necessary for normal execution, + # but is for interactive mode, where we might rebuild the same + # target and need to start from scratch. + self.del_binfo() + self.clear_memoized_values() + self.ninfo = self.new_ninfo() + self.executor_cleanup() + try: + delattr(self, '_calculated_sig') + except AttributeError: + pass + self.includes = None + + def clear_memoized_values(self): + self._memo = {} + + def builder_set(self, builder): + self.builder = builder + try: + del self.executor + except AttributeError: + pass + + def has_builder(self): + """Return whether this Node has a builder or not. + + In Boolean tests, this turns out to be a *lot* more efficient + than simply examining the builder attribute directly ("if + node.builder: ..."). When the builder attribute is examined + directly, it ends up calling __getattr__ for both the __len__ + and __nonzero__ attributes on instances of our Builder Proxy + class(es), generating a bazillion extra calls and slowing + things down immensely. + """ + try: + b = self.builder + except AttributeError: + # There was no explicit builder for this Node, so initialize + # the self.builder attribute to None now. + b = self.builder = None + return b is not None + + def set_explicit(self, is_explicit): + self.is_explicit = is_explicit + + def has_explicit_builder(self): + """Return whether this Node has an explicit builder + + This allows an internal Builder created by SCons to be marked + non-explicit, so that it can be overridden by an explicit + builder that the user supplies (the canonical example being + directories).""" + try: + return self.is_explicit + except AttributeError: + self.is_explicit = None + return self.is_explicit + + def get_builder(self, default_builder=None): + """Return the set builder, or a specified default value""" + try: + return self.builder + except AttributeError: + return default_builder + + multiple_side_effect_has_builder = has_builder + + def is_derived(self): + """ + Returns true if this node is derived (i.e. built). + + This should return true only for nodes whose path should be in + the variant directory when duplicate=0 and should contribute their build + signatures when they are used as source files to other derived files. For + example: source with source builders are not derived in this sense, + and hence should not return true. + """ + return _is_derived_map[self._func_is_derived](self) + + def alter_targets(self): + """Return a list of alternate targets for this Node. + """ + return [], None + + def get_found_includes(self, env, scanner, path): + """Return the scanned include lines (implicit dependencies) + found in this node. + + The default is no implicit dependencies. We expect this method + to be overridden by any subclass that can be scanned for + implicit dependencies. + """ + return [] + + def get_implicit_deps(self, env, initial_scanner, path_func, kw = {}): + """Return a list of implicit dependencies for this node. + + This method exists to handle recursive invocation of the scanner + on the implicit dependencies returned by the scanner, if the + scanner's recursive flag says that we should. + """ + nodes = [self] + seen = set(nodes) + dependencies = [] + path_memo = {} + + root_node_scanner = self._get_scanner(env, initial_scanner, None, kw) + + while nodes: + node = nodes.pop(0) + + scanner = node._get_scanner(env, initial_scanner, root_node_scanner, kw) + if not scanner: + continue + + try: + path = path_memo[scanner] + except KeyError: + path = path_func(scanner) + path_memo[scanner] = path + + included_deps = [x for x in node.get_found_includes(env, scanner, path) if x not in seen] + if included_deps: + dependencies.extend(included_deps) + seen.update(included_deps) + nodes.extend(scanner.recurse_nodes(included_deps)) + + return dependencies + + def _get_scanner(self, env, initial_scanner, root_node_scanner, kw): + if initial_scanner: + # handle explicit scanner case + scanner = initial_scanner.select(self) + else: + # handle implicit scanner case + scanner = self.get_env_scanner(env, kw) + if scanner: + scanner = scanner.select(self) + + if not scanner: + # no scanner could be found for the given node's scanner key; + # thus, make an attempt at using a default. + scanner = root_node_scanner + + return scanner + + def get_env_scanner(self, env, kw={}): + return env.get_scanner(self.scanner_key()) + + def get_target_scanner(self): + return self.builder.target_scanner + + def get_source_scanner(self, node): + """Fetch the source scanner for the specified node + + NOTE: "self" is the target being built, "node" is + the source file for which we want to fetch the scanner. + + Implies self.has_builder() is true; again, expect to only be + called from locations where this is already verified. + + This function may be called very often; it attempts to cache + the scanner found to improve performance. + """ + scanner = None + try: + scanner = self.builder.source_scanner + except AttributeError: + pass + if not scanner: + # The builder didn't have an explicit scanner, so go look up + # a scanner from env['SCANNERS'] based on the node's scanner + # key (usually the file extension). + scanner = self.get_env_scanner(self.get_build_env()) + if scanner: + scanner = scanner.select(node) + return scanner + + def add_to_implicit(self, deps): + if not hasattr(self, 'implicit') or self.implicit is None: + self.implicit = [] + self.implicit_set = set() + self._children_reset() + self._add_child(self.implicit, self.implicit_set, deps) + + def scan(self): + """Scan this node's dependents for implicit dependencies.""" + # Don't bother scanning non-derived files, because we don't + # care what their dependencies are. + # Don't scan again, if we already have scanned. + if self.implicit is not None: + return + self.implicit = [] + self.implicit_set = set() + self._children_reset() + if not self.has_builder(): + return + + build_env = self.get_build_env() + executor = self.get_executor() + + # Here's where we implement --implicit-cache. + if implicit_cache and not implicit_deps_changed: + implicit = self.get_stored_implicit() + if implicit is not None: + # We now add the implicit dependencies returned from the + # stored .sconsign entry to have already been converted + # to Nodes for us. (We used to run them through a + # source_factory function here.) + + # Update all of the targets with them. This + # essentially short-circuits an N*M scan of the + # sources for each individual target, which is a hell + # of a lot more efficient. + for tgt in executor.get_all_targets(): + tgt.add_to_implicit(implicit) + + if implicit_deps_unchanged or self.is_up_to_date(): + return + # one of this node's sources has changed, + # so we must recalculate the implicit deps for all targets + for tgt in executor.get_all_targets(): + tgt.implicit = [] + tgt.implicit_set = set() + + # Have the executor scan the sources. + executor.scan_sources(self.builder.source_scanner) + + # If there's a target scanner, have the executor scan the target + # node itself and associated targets that might be built. + scanner = self.get_target_scanner() + if scanner: + executor.scan_targets(scanner) + + def scanner_key(self): + return None + + def select_scanner(self, scanner): + """Selects a scanner for this Node. + + This is a separate method so it can be overridden by Node + subclasses (specifically, Node.FS.Dir) that *must* use their + own Scanner and don't select one the Scanner.Selector that's + configured for the target. + """ + return scanner.select(self) + + def env_set(self, env, safe=0): + if safe and self.env: + return + self.env = env + + # + # SIGNATURE SUBSYSTEM + # + + NodeInfo = NodeInfoBase + BuildInfo = BuildInfoBase + + def new_ninfo(self): + ninfo = self.NodeInfo() + return ninfo + + def get_ninfo(self): + try: + return self.ninfo + except AttributeError: + self.ninfo = self.new_ninfo() + return self.ninfo + + def new_binfo(self): + binfo = self.BuildInfo() + return binfo + + def get_binfo(self): + """ + Fetch a node's build information. + + node - the node whose sources will be collected + cache - alternate node to use for the signature cache + returns - the build signature + + This no longer handles the recursive descent of the + node's children's signatures. We expect that they're + already built and updated by someone else, if that's + what's wanted. + """ + try: + return self.binfo + except AttributeError: + pass + + binfo = self.new_binfo() + self.binfo = binfo + + executor = self.get_executor() + ignore_set = self.ignore_set + + if self.has_builder(): + binfo.bact = str(executor) + binfo.bactsig = SCons.Util.MD5signature(executor.get_contents()) + + if self._specific_sources: + sources = [s for s in self.sources if not s in ignore_set] + + else: + sources = executor.get_unignored_sources(self, self.ignore) + + seen = set() + binfo.bsources = [s for s in sources if s not in seen and not seen.add(s)] + binfo.bsourcesigs = [s.get_ninfo() for s in binfo.bsources] + + binfo.bdepends = [d for d in self.depends if d not in ignore_set] + binfo.bdependsigs = [d.get_ninfo() for d in self.depends] + + # Because self.implicit is initialized to None (and not empty list []) + # we have to handle this case + if not self.implicit: + binfo.bimplicit = [] + binfo.bimplicitsigs = [] + else: + binfo.bimplicit = [i for i in self.implicit if i not in ignore_set] + binfo.bimplicitsigs = [i.get_ninfo() for i in binfo.bimplicit] + + return binfo + + def del_binfo(self): + """Delete the build info from this node.""" + try: + delattr(self, 'binfo') + except AttributeError: + pass + + def get_csig(self): + try: + return self.ninfo.csig + except AttributeError: + ninfo = self.get_ninfo() + ninfo.csig = SCons.Util.MD5signature(self.get_contents()) + return self.ninfo.csig + + def get_cachedir_csig(self): + return self.get_csig() + + def get_stored_info(self): + return None + + def get_stored_implicit(self): + """Fetch the stored implicit dependencies""" + return None + + # + # + # + + def set_precious(self, precious = 1): + """Set the Node's precious value.""" + self.precious = precious + + def set_pseudo(self, pseudo = True): + """Set the Node's precious value.""" + self.pseudo = pseudo + + def set_noclean(self, noclean = 1): + """Set the Node's noclean value.""" + # Make sure noclean is an integer so the --debug=stree + # output in Util.py can use it as an index. + self.noclean = noclean and 1 or 0 + + def set_nocache(self, nocache = 1): + """Set the Node's nocache value.""" + # Make sure nocache is an integer so the --debug=stree + # output in Util.py can use it as an index. + self.nocache = nocache and 1 or 0 + + def set_always_build(self, always_build = 1): + """Set the Node's always_build value.""" + self.always_build = always_build + + def exists(self): + """Does this node exists?""" + return _exists_map[self._func_exists](self) + + def rexists(self): + """Does this node exist locally or in a repository?""" + # There are no repositories by default: + return _rexists_map[self._func_rexists](self) + + def get_contents(self): + """Fetch the contents of the entry.""" + return _get_contents_map[self._func_get_contents](self) + + def missing(self): + return not self.is_derived() and \ + not self.linked and \ + not self.rexists() + + def remove(self): + """Remove this Node: no-op by default.""" + return None + + def add_dependency(self, depend): + """Adds dependencies.""" + try: + self._add_child(self.depends, self.depends_set, depend) + except TypeError as e: + e = e.args[0] + if SCons.Util.is_List(e): + s = list(map(str, e)) + else: + s = str(e) + raise SCons.Errors.UserError("attempted to add a non-Node dependency to %s:\n\t%s is a %s, not a Node" % (str(self), s, type(e))) + + def add_prerequisite(self, prerequisite): + """Adds prerequisites""" + if self.prerequisites is None: + self.prerequisites = SCons.Util.UniqueList() + self.prerequisites.extend(prerequisite) + self._children_reset() + + def add_ignore(self, depend): + """Adds dependencies to ignore.""" + try: + self._add_child(self.ignore, self.ignore_set, depend) + except TypeError as e: + e = e.args[0] + if SCons.Util.is_List(e): + s = list(map(str, e)) + else: + s = str(e) + raise SCons.Errors.UserError("attempted to ignore a non-Node dependency of %s:\n\t%s is a %s, not a Node" % (str(self), s, type(e))) + + def add_source(self, source): + """Adds sources.""" + if self._specific_sources: + return + try: + self._add_child(self.sources, self.sources_set, source) + except TypeError as e: + e = e.args[0] + if SCons.Util.is_List(e): + s = list(map(str, e)) + else: + s = str(e) + raise SCons.Errors.UserError("attempted to add a non-Node as source of %s:\n\t%s is a %s, not a Node" % (str(self), s, type(e))) + + def _add_child(self, collection, set, child): + """Adds 'child' to 'collection', first checking 'set' to see if it's + already present.""" + added = None + for c in child: + if c not in set: + set.add(c) + collection.append(c) + added = 1 + if added: + self._children_reset() + + def set_specific_source(self, source): + self.add_source(source) + self._specific_sources = True + + def add_wkid(self, wkid): + """Add a node to the list of kids waiting to be evaluated""" + if self.wkids is not None: + self.wkids.append(wkid) + + def _children_reset(self): + self.clear_memoized_values() + # We need to let the Executor clear out any calculated + # build info that it's cached so we can re-calculate it. + self.executor_cleanup() + + @SCons.Memoize.CountMethodCall + def _children_get(self): + try: + return self._memo['_children_get'] + except KeyError: + pass + + # The return list may contain duplicate Nodes, especially in + # source trees where there are a lot of repeated #includes + # of a tangle of .h files. Profiling shows, however, that + # eliminating the duplicates with a brute-force approach that + # preserves the order (that is, something like: + # + # u = [] + # for n in list: + # if n not in u: + # u.append(n)" + # + # takes more cycles than just letting the underlying methods + # hand back cached values if a Node's information is requested + # multiple times. (Other methods of removing duplicates, like + # using dictionary keys, lose the order, and the only ordered + # dictionary patterns I found all ended up using "not in" + # internally anyway...) + if self.ignore_set: + iter = chain.from_iterable([_f for _f in [self.sources, self.depends, self.implicit] if _f]) + + children = [] + for i in iter: + if i not in self.ignore_set: + children.append(i) + else: + children = self.all_children(scan=0) + + self._memo['_children_get'] = children + return children + + def all_children(self, scan=1): + """Return a list of all the node's direct children.""" + if scan: + self.scan() + + # The return list may contain duplicate Nodes, especially in + # source trees where there are a lot of repeated #includes + # of a tangle of .h files. Profiling shows, however, that + # eliminating the duplicates with a brute-force approach that + # preserves the order (that is, something like: + # + # u = [] + # for n in list: + # if n not in u: + # u.append(n)" + # + # takes more cycles than just letting the underlying methods + # hand back cached values if a Node's information is requested + # multiple times. (Other methods of removing duplicates, like + # using dictionary keys, lose the order, and the only ordered + # dictionary patterns I found all ended up using "not in" + # internally anyway...) + return list(chain.from_iterable([_f for _f in [self.sources, self.depends, self.implicit] if _f])) + + def children(self, scan=1): + """Return a list of the node's direct children, minus those + that are ignored by this node.""" + if scan: + self.scan() + return self._children_get() + + def set_state(self, state): + self.state = state + + def get_state(self): + return self.state + + def get_env(self): + env = self.env + if not env: + import SCons.Defaults + env = SCons.Defaults.DefaultEnvironment() + return env + + def Decider(self, function): + foundkey = None + for k, v in _decider_map.items(): + if v == function: + foundkey = k + break + if not foundkey: + foundkey = len(_decider_map) + _decider_map[foundkey] = function + self.changed_since_last_build = foundkey + + def Tag(self, key, value): + """ Add a user-defined tag. """ + if not self._tags: + self._tags = {} + self._tags[key] = value + + def GetTag(self, key): + """ Return a user-defined tag. """ + if not self._tags: + return None + return self._tags.get(key, None) + + def changed(self, node=None, allowcache=False): + """ + Returns if the node is up-to-date with respect to the BuildInfo + stored last time it was built. The default behavior is to compare + it against our own previously stored BuildInfo, but the stored + BuildInfo from another Node (typically one in a Repository) + can be used instead. + + Note that we now *always* check every dependency. We used to + short-circuit the check by returning as soon as we detected + any difference, but we now rely on checking every dependency + to make sure that any necessary Node information (for example, + the content signature of an #included .h file) is updated. + + The allowcache option was added for supporting the early + release of the executor/builder structures, right after + a File target was built. When set to true, the return + value of this changed method gets cached for File nodes. + Like this, the executor isn't needed any longer for subsequent + calls to changed(). + + @see: FS.File.changed(), FS.File.release_target_info() + """ + t = 0 + if t: Trace('changed(%s [%s], %s)' % (self, classname(self), node)) + if node is None: + node = self + + result = False + + bi = node.get_stored_info().binfo + then = bi.bsourcesigs + bi.bdependsigs + bi.bimplicitsigs + children = self.children() + + diff = len(children) - len(then) + if diff: + # The old and new dependency lists are different lengths. + # This always indicates that the Node must be rebuilt. + # We also extend the old dependency list with enough None + # entries to equal the new dependency list, for the benefit + # of the loop below that updates node information. + then.extend([None] * diff) + if t: Trace(': old %s new %s' % (len(then), len(children))) + result = True + + for child, prev_ni in zip(children, then): + try: + if _decider_map[child.changed_since_last_build](child, self, prev_ni): + if t: Trace(': %s changed' % child) + result = True + except DeciderNeedsNode as e: + if e.decider(self, prev_ni, node=node): + if t: Trace(': %s changed' % child) + result = True + + if self.has_builder(): + import SCons.Util + contents = self.get_executor().get_contents() + newsig = SCons.Util.MD5signature(contents) + if bi.bactsig != newsig: + if t: Trace(': bactsig %s != newsig %s' % (bi.bactsig, newsig)) + result = True + + if not result: + if t: Trace(': up to date') + + if t: Trace('\n') + + return result + + def is_up_to_date(self): + """Default check for whether the Node is current: unknown Node + subtypes are always out of date, so they will always get built.""" + return None + + def children_are_up_to_date(self): + """Alternate check for whether the Node is current: If all of + our children were up-to-date, then this Node was up-to-date, too. + + The SCons.Node.Alias and SCons.Node.Python.Value subclasses + rebind their current() method to this method.""" + # Allow the children to calculate their signatures. + self.binfo = self.get_binfo() + if self.always_build: + return None + state = 0 + for kid in self.children(None): + s = kid.get_state() + if s and (not state or s > state): + state = s + return (state == 0 or state == SCons.Node.up_to_date) + + def is_literal(self): + """Always pass the string representation of a Node to + the command interpreter literally.""" + return 1 + + def render_include_tree(self): + """ + Return a text representation, suitable for displaying to the + user, of the include tree for the sources of this node. + """ + if self.is_derived(): + env = self.get_build_env() + if env: + for s in self.sources: + scanner = self.get_source_scanner(s) + if scanner: + path = self.get_build_scanner_path(scanner) + else: + path = None + def f(node, env=env, scanner=scanner, path=path): + return node.get_found_includes(env, scanner, path) + return SCons.Util.render_tree(s, f, 1) + else: + return None + + def get_abspath(self): + """ + Return an absolute path to the Node. This will return simply + str(Node) by default, but for Node types that have a concept of + relative path, this might return something different. + """ + return str(self) + + def for_signature(self): + """ + Return a string representation of the Node that will always + be the same for this particular Node, no matter what. This + is by contrast to the __str__() method, which might, for + instance, return a relative path for a file Node. The purpose + of this method is to generate a value to be used in signature + calculation for the command line used to build a target, and + we use this method instead of str() to avoid unnecessary + rebuilds. This method does not need to return something that + would actually work in a command line; it can return any kind of + nonsense, so long as it does not change. + """ + return str(self) + + def get_string(self, for_signature): + """This is a convenience function designed primarily to be + used in command generators (i.e., CommandGeneratorActions or + Environment variables that are callable), which are called + with a for_signature argument that is nonzero if the command + generator is being called to generate a signature for the + command line, which determines if we should rebuild or not. + + Such command generators should use this method in preference + to str(Node) when converting a Node to a string, passing + in the for_signature parameter, such that we will call + Node.for_signature() or str(Node) properly, depending on whether + we are calculating a signature or actually constructing a + command line.""" + if for_signature: + return self.for_signature() + return str(self) + + def get_subst_proxy(self): + """ + This method is expected to return an object that will function + exactly like this Node, except that it implements any additional + special features that we would like to be in effect for + Environment variable substitution. The principle use is that + some Nodes would like to implement a __getattr__() method, + but putting that in the Node type itself has a tendency to kill + performance. We instead put it in a proxy and return it from + this method. It is legal for this method to return self + if no new functionality is needed for Environment substitution. + """ + return self + + def explain(self): + if not self.exists(): + return "building `%s' because it doesn't exist\n" % self + + if self.always_build: + return "rebuilding `%s' because AlwaysBuild() is specified\n" % self + + old = self.get_stored_info() + if old is None: + return None + + old = old.binfo + old.prepare_dependencies() + + try: + old_bkids = old.bsources + old.bdepends + old.bimplicit + old_bkidsigs = old.bsourcesigs + old.bdependsigs + old.bimplicitsigs + except AttributeError: + return "Cannot explain why `%s' is being rebuilt: No previous build information found\n" % self + + new = self.get_binfo() + + new_bkids = new.bsources + new.bdepends + new.bimplicit + new_bkidsigs = new.bsourcesigs + new.bdependsigs + new.bimplicitsigs + + osig = dict(list(zip(old_bkids, old_bkidsigs))) + nsig = dict(list(zip(new_bkids, new_bkidsigs))) + + # The sources and dependencies we'll want to report are all stored + # as relative paths to this target's directory, but we want to + # report them relative to the top-level SConstruct directory, + # so we only print them after running them through this lambda + # to turn them into the right relative Node and then return + # its string. + def stringify( s, E=self.dir.Entry): + if hasattr( s, 'dir' ) : + return str(E(s)) + return str(s) + + lines = [] + + removed = [x for x in old_bkids if not x in new_bkids] + if removed: + removed = [stringify(r) for r in removed] + fmt = "`%s' is no longer a dependency\n" + lines.extend([fmt % s for s in removed]) + + for k in new_bkids: + if not k in old_bkids: + lines.append("`%s' is a new dependency\n" % stringify(k)) + else: + try: + changed = _decider_map[k.changed_since_last_build](k, self, osig[k]) + except DeciderNeedsNode as e: + changed = e.decider(self, osig[k], node=self) + + if changed: + lines.append("`%s' changed\n" % stringify(k)) + + if len(lines) == 0 and old_bkids != new_bkids: + lines.append("the dependency order changed:\n" + + "%sold: %s\n" % (' '*15, list(map(stringify, old_bkids))) + + "%snew: %s\n" % (' '*15, list(map(stringify, new_bkids)))) + + if len(lines) == 0: + def fmt_with_title(title, strlines): + lines = strlines.split('\n') + sep = '\n' + ' '*(15 + len(title)) + return ' '*15 + title + sep.join(lines) + '\n' + if old.bactsig != new.bactsig: + if old.bact == new.bact: + lines.append("the contents of the build action changed\n" + + fmt_with_title('action: ', new.bact)) + + # lines.append("the contents of the build action changed [%s] [%s]\n"%(old.bactsig,new.bactsig) + + # fmt_with_title('action: ', new.bact)) + else: + lines.append("the build action changed:\n" + + fmt_with_title('old: ', old.bact) + + fmt_with_title('new: ', new.bact)) + + if len(lines) == 0: + return "rebuilding `%s' for unknown reasons\n" % self + + preamble = "rebuilding `%s' because" % self + if len(lines) == 1: + return "%s %s" % (preamble, lines[0]) + else: + lines = ["%s:\n" % preamble] + lines + return ( ' '*11).join(lines) + +class NodeList(collections.UserList): + def __str__(self): + return str(list(map(str, self.data))) + +def get_children(node, parent): return node.children() +def ignore_cycle(node, stack): pass +def do_nothing(node, parent): pass + +class Walker(object): + """An iterator for walking a Node tree. + + This is depth-first, children are visited before the parent. + The Walker object can be initialized with any node, and + returns the next node on the descent with each get_next() call. + 'kids_func' is an optional function that will be called to + get the children of a node instead of calling 'children'. + 'cycle_func' is an optional function that will be called + when a cycle is detected. + + This class does not get caught in node cycles caused, for example, + by C header file include loops. + """ + def __init__(self, node, kids_func=get_children, + cycle_func=ignore_cycle, + eval_func=do_nothing): + self.kids_func = kids_func + self.cycle_func = cycle_func + self.eval_func = eval_func + node.wkids = copy.copy(kids_func(node, None)) + self.stack = [node] + self.history = {} # used to efficiently detect and avoid cycles + self.history[node] = None + + def get_next(self): + """Return the next node for this walk of the tree. + + This function is intentionally iterative, not recursive, + to sidestep any issues of stack size limitations. + """ + + while self.stack: + if self.stack[-1].wkids: + node = self.stack[-1].wkids.pop(0) + if not self.stack[-1].wkids: + self.stack[-1].wkids = None + if node in self.history: + self.cycle_func(node, self.stack) + else: + node.wkids = copy.copy(self.kids_func(node, self.stack[-1])) + self.stack.append(node) + self.history[node] = None + else: + node = self.stack.pop() + del self.history[node] + if node: + if self.stack: + parent = self.stack[-1] + else: + parent = None + self.eval_func(node, parent) + return node + return None + + def is_done(self): + return not self.stack + + +arg2nodes_lookups = [] + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/PathList.py b/tools/scons/scons-local-3.0.5/SCons/PathList.py new file mode 100755 index 0000000000..fa73a9d6a2 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/PathList.py @@ -0,0 +1,227 @@ +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/PathList.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +__doc__ = """SCons.PathList + +A module for handling lists of directory paths (the sort of things +that get set as CPPPATH, LIBPATH, etc.) with as much caching of data and +efficiency as we can, while still keeping the evaluation delayed so that we +Do the Right Thing (almost) regardless of how the variable is specified. + +""" + +import os + +import SCons.Memoize +import SCons.Node +import SCons.Util + +# +# Variables to specify the different types of entries in a PathList object: +# + +TYPE_STRING_NO_SUBST = 0 # string with no '$' +TYPE_STRING_SUBST = 1 # string containing '$' +TYPE_OBJECT = 2 # other object + +def node_conv(obj): + """ + This is the "string conversion" routine that we have our substitutions + use to return Nodes, not strings. This relies on the fact that an + EntryProxy object has a get() method that returns the underlying + Node that it wraps, which is a bit of architectural dependence + that we might need to break or modify in the future in response to + additional requirements. + """ + try: + get = obj.get + except AttributeError: + if isinstance(obj, SCons.Node.Node) or SCons.Util.is_Sequence( obj ): + result = obj + else: + result = str(obj) + else: + result = get() + return result + +class _PathList(object): + """ + An actual PathList object. + """ + def __init__(self, pathlist): + """ + Initializes a PathList object, canonicalizing the input and + pre-processing it for quicker substitution later. + + The stored representation of the PathList is a list of tuples + containing (type, value), where the "type" is one of the TYPE_* + variables defined above. We distinguish between: + + strings that contain no '$' and therefore need no + delayed-evaluation string substitution (we expect that there + will be many of these and that we therefore get a pretty + big win from avoiding string substitution) + + strings that contain '$' and therefore need substitution + (the hard case is things like '${TARGET.dir}/include', + which require re-evaluation for every target + source) + + other objects (which may be something like an EntryProxy + that needs a method called to return a Node) + + Pre-identifying the type of each element in the PathList up-front + and storing the type in the list of tuples is intended to reduce + the amount of calculation when we actually do the substitution + over and over for each target. + """ + if SCons.Util.is_String(pathlist): + pathlist = pathlist.split(os.pathsep) + elif not SCons.Util.is_Sequence(pathlist): + pathlist = [pathlist] + + pl = [] + for p in pathlist: + try: + found = '$' in p + except (AttributeError, TypeError): + type = TYPE_OBJECT + else: + if not found: + type = TYPE_STRING_NO_SUBST + else: + type = TYPE_STRING_SUBST + pl.append((type, p)) + + self.pathlist = tuple(pl) + + def __len__(self): return len(self.pathlist) + + def __getitem__(self, i): return self.pathlist[i] + + def subst_path(self, env, target, source): + """ + Performs construction variable substitution on a pre-digested + PathList for a specific target and source. + """ + result = [] + for type, value in self.pathlist: + if type == TYPE_STRING_SUBST: + value = env.subst(value, target=target, source=source, + conv=node_conv) + if SCons.Util.is_Sequence(value): + result.extend(SCons.Util.flatten(value)) + elif value: + result.append(value) + elif type == TYPE_OBJECT: + value = node_conv(value) + if value: + result.append(value) + elif value: + result.append(value) + return tuple(result) + + +class PathListCache(object): + """ + A class to handle caching of PathList lookups. + + This class gets instantiated once and then deleted from the namespace, + so it's used as a Singleton (although we don't enforce that in the + usual Pythonic ways). We could have just made the cache a dictionary + in the module namespace, but putting it in this class allows us to + use the same Memoizer pattern that we use elsewhere to count cache + hits and misses, which is very valuable. + + Lookup keys in the cache are computed by the _PathList_key() method. + Cache lookup should be quick, so we don't spend cycles canonicalizing + all forms of the same lookup key. For example, 'x:y' and ['x', + 'y'] logically represent the same list, but we don't bother to + split string representations and treat those two equivalently. + (Note, however, that we do, treat lists and tuples the same.) + + The main type of duplication we're trying to catch will come from + looking up the same path list from two different clones of the + same construction environment. That is, given + + env2 = env1.Clone() + + both env1 and env2 will have the same CPPPATH value, and we can + cheaply avoid re-parsing both values of CPPPATH by using the + common value from this cache. + """ + def __init__(self): + self._memo = {} + + def _PathList_key(self, pathlist): + """ + Returns the key for memoization of PathLists. + + Note that we want this to be pretty quick, so we don't completely + canonicalize all forms of the same list. For example, + 'dir1:$ROOT/dir2' and ['$ROOT/dir1', 'dir'] may logically + represent the same list if you're executing from $ROOT, but + we're not going to bother splitting strings into path elements, + or massaging strings into Nodes, to identify that equivalence. + We just want to eliminate obvious redundancy from the normal + case of re-using exactly the same cloned value for a path. + """ + if SCons.Util.is_Sequence(pathlist): + pathlist = tuple(SCons.Util.flatten(pathlist)) + return pathlist + + @SCons.Memoize.CountDictCall(_PathList_key) + def PathList(self, pathlist): + """ + Returns the cached _PathList object for the specified pathlist, + creating and caching a new object as necessary. + """ + pathlist = self._PathList_key(pathlist) + try: + memo_dict = self._memo['PathList'] + except KeyError: + memo_dict = {} + self._memo['PathList'] = memo_dict + else: + try: + return memo_dict[pathlist] + except KeyError: + pass + + result = _PathList(pathlist) + + memo_dict[pathlist] = result + + return result + +PathList = PathListCache().PathList + + +del PathListCache + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Platform/__init__.py b/tools/scons/scons-local-3.0.5/SCons/Platform/__init__.py new file mode 100755 index 0000000000..e1cc941dda --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Platform/__init__.py @@ -0,0 +1,299 @@ +"""SCons.Platform + +SCons platform selection. + +This looks for modules that define a callable object that can modify a +construction environment as appropriate for a given platform. + +Note that we take a more simplistic view of "platform" than Python does. +We're looking for a single string that determines a set of +tool-independent variables with which to initialize a construction +environment. Consequently, we'll examine both sys.platform and os.name +(and anything else that might come in to play) in order to return some +specification which is unique enough for our purposes. + +Note that because this subsystem just *selects* a callable that can +modify a construction environment, it's possible for people to define +their own "platform specification" in an arbitrary callable function. +No one needs to use or tie in to this subsystem in order to roll +their own platform definition. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +from __future__ import print_function + +__revision__ = "src/engine/SCons/Platform/__init__.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.compat + +import imp +import os +import sys +import tempfile + +import SCons.Errors +import SCons.Subst +import SCons.Tool + + +def platform_default(): + """Return the platform string for our execution environment. + + The returned value should map to one of the SCons/Platform/*.py + files. Since we're architecture independent, though, we don't + care about the machine architecture. + """ + osname = os.name + if osname == 'java': + osname = os._osType + if osname == 'posix': + if sys.platform == 'cygwin': + return 'cygwin' + elif sys.platform.find('irix') != -1: + return 'irix' + elif sys.platform.find('sunos') != -1: + return 'sunos' + elif sys.platform.find('hp-ux') != -1: + return 'hpux' + elif sys.platform.find('aix') != -1: + return 'aix' + elif sys.platform.find('darwin') != -1: + return 'darwin' + else: + return 'posix' + elif os.name == 'os2': + return 'os2' + else: + return sys.platform + + +def platform_module(name = platform_default()): + """Return the imported module for the platform. + + This looks for a module name that matches the specified argument. + If the name is unspecified, we fetch the appropriate default for + our execution environment. + """ + full_name = 'SCons.Platform.' + name + if full_name not in sys.modules: + if os.name == 'java': + eval(full_name) + else: + try: + file, path, desc = imp.find_module(name, + sys.modules['SCons.Platform'].__path__) + try: + mod = imp.load_module(full_name, file, path, desc) + finally: + if file: + file.close() + except ImportError: + try: + import zipimport + importer = zipimport.zipimporter( sys.modules['SCons.Platform'].__path__[0] ) + mod = importer.load_module(full_name) + except ImportError: + raise SCons.Errors.UserError("No platform named '%s'" % name) + setattr(SCons.Platform, name, mod) + return sys.modules[full_name] + + +def DefaultToolList(platform, env): + """Select a default tool list for the specified platform. + """ + return SCons.Tool.tool_list(platform, env) + + +class PlatformSpec(object): + def __init__(self, name, generate): + self.name = name + self.generate = generate + + def __call__(self, *args, **kw): + return self.generate(*args, **kw) + + def __str__(self): + return self.name + + +class TempFileMunge(object): + """A callable class. You can set an Environment variable to this, + then call it with a string argument, then it will perform temporary + file substitution on it. This is used to circumvent the long command + line limitation. + + Example usage: + env["TEMPFILE"] = TempFileMunge + env["LINKCOM"] = "${TEMPFILE('$LINK $TARGET $SOURCES','$LINKCOMSTR')}" + + By default, the name of the temporary file used begins with a + prefix of '@'. This may be configured for other tool chains by + setting '$TEMPFILEPREFIX': + env["TEMPFILEPREFIX"] = '-@' # diab compiler + env["TEMPFILEPREFIX"] = '-via' # arm tool chain + env["TEMPFILEPREFIX"] = '' # (the empty string) PC Lint + + You can configure the extension of the temporary file through the + TEMPFILESUFFIX variable, which defaults to '.lnk' (see comments + in the code below): + env["TEMPFILESUFFIX"] = '.lnt' # PC Lint + """ + def __init__(self, cmd, cmdstr = None): + self.cmd = cmd + self.cmdstr = cmdstr + + def __call__(self, target, source, env, for_signature): + if for_signature: + # If we're being called for signature calculation, it's + # because we're being called by the string expansion in + # Subst.py, which has the logic to strip any $( $) that + # may be in the command line we squirreled away. So we + # just return the raw command line and let the upper + # string substitution layers do their thing. + return self.cmd + + # Now we're actually being called because someone is actually + # going to try to execute the command, so we have to do our + # own expansion. + cmd = env.subst_list(self.cmd, SCons.Subst.SUBST_CMD, target, source)[0] + try: + maxline = int(env.subst('$MAXLINELENGTH')) + except ValueError: + maxline = 2048 + + length = 0 + for c in cmd: + length += len(c) + length += len(cmd) - 1 + if length <= maxline: + return self.cmd + + # Check if we already created the temporary file for this target + # It should have been previously done by Action.strfunction() call + node = target[0] if SCons.Util.is_List(target) else target + cmdlist = getattr(node.attributes, 'tempfile_cmdlist', None) \ + if node is not None else None + if cmdlist is not None: + return cmdlist + + # We do a normpath because mktemp() has what appears to be + # a bug in Windows that will use a forward slash as a path + # delimiter. Windows' link mistakes that for a command line + # switch and barfs. + # + # Default to the .lnk suffix for the benefit of the Phar Lap + # linkloc linker, which likes to append an .lnk suffix if + # none is given. + if env.has_key('TEMPFILESUFFIX'): + suffix = env.subst('$TEMPFILESUFFIX') + else: + suffix = '.lnk' + + fd, tmp = tempfile.mkstemp(suffix, text=True) + native_tmp = SCons.Util.get_native_path(os.path.normpath(tmp)) + + if env.get('SHELL', None) == 'sh': + # The sh shell will try to escape the backslashes in the + # path, so unescape them. + native_tmp = native_tmp.replace('\\', r'\\\\') + # In Cygwin, we want to use rm to delete the temporary + # file, because del does not exist in the sh shell. + rm = env.Detect('rm') or 'del' + else: + # Don't use 'rm' if the shell is not sh, because rm won't + # work with the Windows shells (cmd.exe or command.com) or + # Windows path names. + rm = 'del' + + prefix = env.subst('$TEMPFILEPREFIX') + if not prefix: + prefix = '@' + + args = list(map(SCons.Subst.quote_spaces, cmd[1:])) + os.write(fd, bytearray(" ".join(args) + "\n",'utf-8')) + os.close(fd) + # XXX Using the SCons.Action.print_actions value directly + # like this is bogus, but expedient. This class should + # really be rewritten as an Action that defines the + # __call__() and strfunction() methods and lets the + # normal action-execution logic handle whether or not to + # print/execute the action. The problem, though, is all + # of that is decided before we execute this method as + # part of expanding the $TEMPFILE construction variable. + # Consequently, refactoring this will have to wait until + # we get more flexible with allowing Actions to exist + # independently and get strung together arbitrarily like + # Ant tasks. In the meantime, it's going to be more + # user-friendly to not let obsession with architectural + # purity get in the way of just being helpful, so we'll + # reach into SCons.Action directly. + if SCons.Action.print_actions: + cmdstr = env.subst(self.cmdstr, SCons.Subst.SUBST_RAW, target, + source) if self.cmdstr is not None else '' + # Print our message only if XXXCOMSTR returns an empty string + if len(cmdstr) == 0 : + cmdstr = ("Using tempfile "+native_tmp+" for command line:\n"+ + str(cmd[0]) + " " + " ".join(args)) + self._print_cmd_str(target, source, env, cmdstr) + + # Store the temporary file command list into the target Node.attributes + # to avoid creating two temporary files one for print and one for execute. + cmdlist = [ cmd[0], prefix + native_tmp + '\n' + rm, native_tmp ] + if node is not None: + try : + setattr(node.attributes, 'tempfile_cmdlist', cmdlist) + except AttributeError: + pass + return cmdlist + + def _print_cmd_str(self, target, source, env, cmdstr): + # check if the user has specified a cmd line print function + print_func = None + try: + get = env.get + except AttributeError: + pass + else: + print_func = get('PRINT_CMD_LINE_FUNC') + + # use the default action cmd line print if user did not supply one + if not print_func: + action = SCons.Action._ActionAction() + action.print_cmd_line(cmdstr, target, source, env) + else: + print_func(cmdstr, target, source, env) + + +def Platform(name = platform_default()): + """Select a canned Platform specification. + """ + module = platform_module(name) + spec = PlatformSpec(name, module.generate) + return spec + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Platform/aix.py b/tools/scons/scons-local-3.0.5/SCons/Platform/aix.py new file mode 100755 index 0000000000..7faddd990e --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Platform/aix.py @@ -0,0 +1,85 @@ +"""engine.SCons.Platform.aix + +Platform-specific initialization for IBM AIX systems. + +There normally shouldn't be any need to import this module directly. It +will usually be imported through the generic SCons.Platform.Platform() +selection method. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Platform/aix.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os +import subprocess + +from . import posix + +import SCons.Util +import SCons.Action + +def get_xlc(env, xlc=None, packages=[]): + # Use the AIX package installer tool lslpp to figure out where a + # given xl* compiler is installed and what version it is. + xlcPath = None + xlcVersion = None + + if xlc is None: + xlc = env.get('CC', 'xlc') + if SCons.Util.is_List(xlc): + xlc = xlc[0] + for package in packages: + # find the installed filename, which may be a symlink as well + pipe = SCons.Action._subproc(env, ['lslpp', '-fc', package], + stdin = 'devnull', + stderr = 'devnull', + stdout = subprocess.PIPE) + # output of lslpp is something like this: + # #Path:Fileset:File + # /usr/lib/objrepos:vac.C 6.0.0.0:/usr/vac/exe/xlCcpp + # /usr/lib/objrepos:vac.C 6.0.0.0:/usr/vac/bin/xlc_r -> /usr/vac/bin/xlc + for line in pipe.stdout: + if xlcPath: + continue # read everything to let lslpp terminate + fileset, filename = line.split(':')[1:3] + filename = filename.split()[0] + if ('/' in xlc and filename == xlc) \ + or ('/' not in xlc and filename.endswith('/' + xlc)): + xlcVersion = fileset.split()[1] + xlcPath, sep, xlc = filename.rpartition('/') + pass + pass + return (xlcPath, xlc, xlcVersion) + +def generate(env): + posix.generate(env) + #Based on AIX 5.2: ARG_MAX=24576 - 3000 for environment expansion + env['MAXLINELENGTH'] = 21576 + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Platform/cygwin.py b/tools/scons/scons-local-3.0.5/SCons/Platform/cygwin.py new file mode 100755 index 0000000000..434d125536 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Platform/cygwin.py @@ -0,0 +1,64 @@ +"""SCons.Platform.cygwin + +Platform-specific initialization for Cygwin systems. + +There normally shouldn't be any need to import this module directly. It +will usually be imported through the generic SCons.Platform.Platform() +selection method. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Platform/cygwin.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import sys + +from . import posix +from SCons.Platform import TempFileMunge + +CYGWIN_DEFAULT_PATHS = [] +if sys.platform == 'win32': + CYGWIN_DEFAULT_PATHS = [ + r'C:\cygwin64\bin', + r'C:\cygwin\bin' + ] + +def generate(env): + posix.generate(env) + + env['PROGPREFIX'] = '' + env['PROGSUFFIX'] = '.exe' + env['SHLIBPREFIX'] = '' + env['SHLIBSUFFIX'] = '.dll' + env['LIBPREFIXES'] = [ '$LIBPREFIX', '$SHLIBPREFIX', '$IMPLIBPREFIX' ] + env['LIBSUFFIXES'] = [ '$LIBSUFFIX', '$SHLIBSUFFIX', '$IMPLIBSUFFIX' ] + env['TEMPFILE'] = TempFileMunge + env['TEMPFILEPREFIX'] = '@' + env['MAXLINELENGTH'] = 2048 + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Platform/darwin.py b/tools/scons/scons-local-3.0.5/SCons/Platform/darwin.py new file mode 100755 index 0000000000..7f4b468a96 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Platform/darwin.py @@ -0,0 +1,74 @@ +"""engine.SCons.Platform.darwin + +Platform-specific initialization for Mac OS X systems. + +There normally shouldn't be any need to import this module directly. It +will usually be imported through the generic SCons.Platform.Platform() +selection method. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Platform/darwin.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +from . import posix +import os + +def generate(env): + posix.generate(env) + env['SHLIBSUFFIX'] = '.dylib' + # put macports paths at front to override Apple's versions, fink path is after + # For now let people who want Macports or Fink tools specify it! + # env['ENV']['PATH'] = '/opt/local/bin:/opt/local/sbin:' + env['ENV']['PATH'] + ':/sw/bin' + + # Store extra system paths in env['ENV']['PATHOSX'] + + filelist = ['/etc/paths',] + # make sure this works on Macs with Tiger or earlier + try: + dirlist = os.listdir('/etc/paths.d') + except: + dirlist = [] + + for file in dirlist: + filelist.append('/etc/paths.d/'+file) + + for file in filelist: + if os.path.isfile(file): + f = open(file, 'r') + lines = f.readlines() + for line in lines: + if line: + env.AppendENVPath('PATHOSX', line.strip('\n')) + f.close() + + # Not sure why this wasn't the case all along? + if env['ENV'].get('PATHOSX', False) and os.environ.get('SCONS_USE_MAC_PATHS', False): + env.AppendENVPath('PATH',env['ENV']['PATHOSX']) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Platform/hpux.py b/tools/scons/scons-local-3.0.5/SCons/Platform/hpux.py new file mode 100755 index 0000000000..cc97d39eef --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Platform/hpux.py @@ -0,0 +1,46 @@ +"""engine.SCons.Platform.hpux + +Platform-specific initialization for HP-UX systems. + +There normally shouldn't be any need to import this module directly. It +will usually be imported through the generic SCons.Platform.Platform() +selection method. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Platform/hpux.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +from . import posix + +def generate(env): + posix.generate(env) + #Based on HP-UX11i: ARG_MAX=2048000 - 3000 for environment expansion + env['MAXLINELENGTH'] = 2045000 + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Platform/irix.py b/tools/scons/scons-local-3.0.5/SCons/Platform/irix.py new file mode 100755 index 0000000000..5df080a08e --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Platform/irix.py @@ -0,0 +1,44 @@ +"""SCons.Platform.irix + +Platform-specific initialization for SGI IRIX systems. + +There normally shouldn't be any need to import this module directly. It +will usually be imported through the generic SCons.Platform.Platform() +selection method. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Platform/irix.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +from . import posix + +def generate(env): + posix.generate(env) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Platform/mingw.py b/tools/scons/scons-local-3.0.5/SCons/Platform/mingw.py new file mode 100755 index 0000000000..f3f7e4498c --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Platform/mingw.py @@ -0,0 +1,39 @@ +"""SCons.Platform.mingw + +Platform-specific initialization for the MinGW system. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Platform/mingw.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import sys + +MINGW_DEFAULT_PATHS = [] +if sys.platform == 'win32': + MINGW_DEFAULT_PATHS = [ + r'C:\msys64', + r'C:\msys' + ] \ No newline at end of file diff --git a/tools/scons/scons-local-3.0.5/SCons/Platform/os2.py b/tools/scons/scons-local-3.0.5/SCons/Platform/os2.py new file mode 100755 index 0000000000..a680f940ce --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Platform/os2.py @@ -0,0 +1,58 @@ +"""SCons.Platform.os2 + +Platform-specific initialization for OS/2 systems. + +There normally shouldn't be any need to import this module directly. It +will usually be imported through the generic SCons.Platform.Platform() +selection method. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Platform/os2.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" +from . import win32 + +def generate(env): + if 'ENV' not in env: + env['ENV'] = {} + env['OBJPREFIX'] = '' + env['OBJSUFFIX'] = '.obj' + env['SHOBJPREFIX'] = '$OBJPREFIX' + env['SHOBJSUFFIX'] = '$OBJSUFFIX' + env['PROGPREFIX'] = '' + env['PROGSUFFIX'] = '.exe' + env['LIBPREFIX'] = '' + env['LIBSUFFIX'] = '.lib' + env['SHLIBPREFIX'] = '' + env['SHLIBSUFFIX'] = '.dll' + env['LIBPREFIXES'] = '$LIBPREFIX' + env['LIBSUFFIXES'] = [ '$LIBSUFFIX', '$SHLIBSUFFIX' ] + env['HOST_OS'] = 'os2' + env['HOST_ARCH'] = win32.get_architecture().arch + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Platform/posix.py b/tools/scons/scons-local-3.0.5/SCons/Platform/posix.py new file mode 100755 index 0000000000..aa43f51276 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Platform/posix.py @@ -0,0 +1,131 @@ +"""SCons.Platform.posix + +Platform-specific initialization for POSIX (Linux, UNIX, etc.) systems. + +There normally shouldn't be any need to import this module directly. It +will usually be imported through the generic SCons.Platform.Platform() +selection method. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Platform/posix.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import errno +import os +import os.path +import subprocess +import sys +import select + +import SCons.Util +from SCons.Platform import TempFileMunge +from SCons.Platform.virtualenv import ImportVirtualenv +from SCons.Platform.virtualenv import ignore_virtualenv, enable_virtualenv + +exitvalmap = { + 2 : 127, + 13 : 126, +} + +def escape(arg): + """escape shell special characters""" + slash = '\\' + special = '"$' + + arg = arg.replace(slash, slash+slash) + for c in special: + arg = arg.replace(c, slash+c) + + # print("ESCAPE RESULT: %s" % arg) + return '"' + arg + '"' + + +def exec_subprocess(l, env): + proc = subprocess.Popen(l, env = env, close_fds = True) + return proc.wait() + +def subprocess_spawn(sh, escape, cmd, args, env): + return exec_subprocess([sh, '-c', ' '.join(args)], env) + +def exec_popen3(l, env, stdout, stderr): + proc = subprocess.Popen(l, env = env, close_fds = True, + stdout = stdout, + stderr = stderr) + return proc.wait() + +def piped_env_spawn(sh, escape, cmd, args, env, stdout, stderr): + # spawn using Popen3 combined with the env command + # the command name and the command's stdout is written to stdout + # the command's stderr is written to stderr + return exec_popen3([sh, '-c', ' '.join(args)], + env, stdout, stderr) + + +def generate(env): + # Bearing in mind we have python 2.4 as a baseline, we can just do this: + spawn = subprocess_spawn + pspawn = piped_env_spawn + # Note that this means that 'escape' is no longer used + + if 'ENV' not in env: + env['ENV'] = {} + env['ENV']['PATH'] = '/usr/local/bin:/opt/bin:/bin:/usr/bin' + env['OBJPREFIX'] = '' + env['OBJSUFFIX'] = '.o' + env['SHOBJPREFIX'] = '$OBJPREFIX' + env['SHOBJSUFFIX'] = '$OBJSUFFIX' + env['PROGPREFIX'] = '' + env['PROGSUFFIX'] = '' + env['LIBPREFIX'] = 'lib' + env['LIBSUFFIX'] = '.a' + env['SHLIBPREFIX'] = '$LIBPREFIX' + env['SHLIBSUFFIX'] = '.so' + env['LIBPREFIXES'] = [ '$LIBPREFIX' ] + env['LIBSUFFIXES'] = [ '$LIBSUFFIX', '$SHLIBSUFFIX' ] + env['PSPAWN'] = pspawn + env['SPAWN'] = spawn + env['SHELL'] = 'sh' + env['ESCAPE'] = escape + env['TEMPFILE'] = TempFileMunge + env['TEMPFILEPREFIX'] = '@' + #Based on LINUX: ARG_MAX=ARG_MAX=131072 - 3000 for environment expansion + #Note: specific platforms might rise or lower this value + env['MAXLINELENGTH'] = 128072 + + # This platform supports RPATH specifications. + env['__RPATH'] = '$_RPATH' + + # GDC is GCC family, but DMD and LDC have different options. + # Must be able to have GCC and DMD work in the same build, so: + env['__DRPATH'] = '$_DRPATH' + + if enable_virtualenv and not ignore_virtualenv: + ImportVirtualenv(env) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Platform/sunos.py b/tools/scons/scons-local-3.0.5/SCons/Platform/sunos.py new file mode 100755 index 0000000000..2ec4c99056 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Platform/sunos.py @@ -0,0 +1,50 @@ +"""engine.SCons.Platform.sunos + +Platform-specific initialization for Sun systems. + +There normally shouldn't be any need to import this module directly. It +will usually be imported through the generic SCons.Platform.Platform() +selection method. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Platform/sunos.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +from . import posix + +def generate(env): + posix.generate(env) + # Based on sunSparc 8:32bit + # ARG_MAX=1048320 - 3000 for environment expansion + env['MAXLINELENGTH'] = 1045320 + env['PKGINFO'] = 'pkginfo' + env['PKGCHK'] = '/usr/sbin/pkgchk' + env['ENV']['PATH'] = env['ENV']['PATH'] + ':/opt/SUNWspro/bin:/usr/ccs/bin' + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Platform/virtualenv.py b/tools/scons/scons-local-3.0.5/SCons/Platform/virtualenv.py new file mode 100755 index 0000000000..4cfb6e13fd --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Platform/virtualenv.py @@ -0,0 +1,120 @@ +"""SCons.Platform.virtualenv + +Support for virtualenv. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Platform/virtualenv.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os +import sys +import SCons.Util + + +virtualenv_enabled_by_default = False + + +def _enable_virtualenv_default(): + return SCons.Util.get_os_env_bool('SCONS_ENABLE_VIRTUALENV', virtualenv_enabled_by_default) + + +def _ignore_virtualenv_default(): + return SCons.Util.get_os_env_bool('SCONS_IGNORE_VIRTUALENV', False) + + +enable_virtualenv = _enable_virtualenv_default() +ignore_virtualenv = _ignore_virtualenv_default() +virtualenv_variables = ['VIRTUAL_ENV', 'PIPENV_ACTIVE'] + + +def _running_in_virtualenv(): + """Returns True, if scons is executed within a virtualenv""" + # see https://stackoverflow.com/a/42580137 + return (hasattr(sys, 'real_prefix') or + (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix)) + + +def _is_path_in(path, base): + """Returns true, if **path** is located under the **base** directory.""" + if not path or not base: # empty path may happen, base too + return False + rp = os.path.relpath(path, base) + return ((not rp.startswith(os.path.pardir)) and (not rp == os.path.curdir)) + + +def _inject_venv_variables(env): + if 'ENV' not in env: + env['ENV'] = {} + ENV = env['ENV'] + for name in virtualenv_variables: + try: + ENV[name] = os.environ[name] + except KeyError: + pass + +def _inject_venv_path(env, path_list=None): + """Modify environment such that SCons will take into account its virtualenv + when running external tools.""" + if path_list is None: + path_list = os.getenv('PATH') + env.PrependENVPath('PATH', select_paths_in_venv(path_list)) + + +def select_paths_in_venv(path_list): + """Returns a list of paths from **path_list** which are under virtualenv's + home directory.""" + if SCons.Util.is_String(path_list): + path_list = path_list.split(os.path.pathsep) + # Find in path_list the paths under the virtualenv's home + return [path for path in path_list if IsInVirtualenv(path)] + + +def ImportVirtualenv(env): + """Copies virtualenv-related environment variables from OS environment + to ``env['ENV']`` and prepends virtualenv's PATH to ``env['ENV']['PATH']``. + """ + _inject_venv_variables(env) + _inject_venv_path(env) + + +def Virtualenv(): + """Returns path to the virtualenv home if scons is executing within a + virtualenv or None, if not.""" + if _running_in_virtualenv(): + return sys.prefix + return None + + +def IsInVirtualenv(path): + """Returns True, if **path** is under virtualenv's home directory. If not, + or if we don't use virtualenv, returns False.""" + return _is_path_in(path, Virtualenv()) + + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Platform/win32.py b/tools/scons/scons-local-3.0.5/SCons/Platform/win32.py new file mode 100755 index 0000000000..756f6d6750 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Platform/win32.py @@ -0,0 +1,471 @@ +"""SCons.Platform.win32 + +Platform-specific initialization for Win32 systems. + +There normally shouldn't be any need to import this module directly. It +will usually be imported through the generic SCons.Platform.Platform() +selection method. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Platform/win32.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os +import os.path +import sys +import tempfile + +from SCons.Platform.posix import exitvalmap +from SCons.Platform import TempFileMunge +from SCons.Platform.virtualenv import ImportVirtualenv +from SCons.Platform.virtualenv import ignore_virtualenv, enable_virtualenv +import SCons.Util + +CHOCO_DEFAULT_PATH = [ + r'C:\ProgramData\chocolatey\bin' +] + +try: + import msvcrt + import win32api + import win32con + + msvcrt.get_osfhandle + win32api.SetHandleInformation + win32con.HANDLE_FLAG_INHERIT +except ImportError: + parallel_msg = \ + "you do not seem to have the pywin32 extensions installed;\n" + \ + "\tparallel (-j) builds may not work reliably with open Python files." +except AttributeError: + parallel_msg = \ + "your pywin32 extensions do not support file handle operations;\n" + \ + "\tparallel (-j) builds may not work reliably with open Python files." +else: + parallel_msg = None + + _builtin_open = open + + def _scons_open(*args, **kw): + fp = _builtin_open(*args, **kw) + win32api.SetHandleInformation(msvcrt.get_osfhandle(fp.fileno()), + win32con.HANDLE_FLAG_INHERIT, + 0) + return fp + + open = _scons_open + + if sys.version_info.major == 2: + _builtin_file = file + class _scons_file(_builtin_file): + def __init__(self, *args, **kw): + _builtin_file.__init__(self, *args, **kw) + win32api.SetHandleInformation(msvcrt.get_osfhandle(self.fileno()), + win32con.HANDLE_FLAG_INHERIT, 0) + file = _scons_file + else: + # No longer needed for python 3.4 and above. Files are opened non sharable + pass + + + +if False: + # Now swap out shutil.filecopy and filecopy2 for win32 api native CopyFile + try: + from ctypes import windll + import shutil + + CopyFile = windll.kernel32.CopyFileA + SetFileTime = windll.kernel32.SetFileTime + + _shutil_copy = shutil.copy + _shutil_copy2 = shutil.copy2 + + shutil.copy2 = CopyFile + + def win_api_copyfile(src,dst): + CopyFile(src,dst) + os.utime(dst) + + shutil.copy = win_api_copyfile + + except AttributeError: + parallel_msg = \ + "Couldn't override shutil.copy or shutil.copy2 falling back to shutil defaults" + + + + + + + +try: + import threading + spawn_lock = threading.Lock() + + # This locked version of spawnve works around a Windows + # MSVCRT bug, because its spawnve is not thread-safe. + # Without this, python can randomly crash while using -jN. + # See the python bug at http://bugs.python.org/issue6476 + # and SCons issue at + # https://github.com/SCons/scons/issues/2449 + def spawnve(mode, file, args, env): + spawn_lock.acquire() + try: + if mode == os.P_WAIT: + ret = os.spawnve(os.P_NOWAIT, file, args, env) + else: + ret = os.spawnve(mode, file, args, env) + finally: + spawn_lock.release() + if mode == os.P_WAIT: + pid, status = os.waitpid(ret, 0) + ret = status >> 8 + return ret +except ImportError: + # Use the unsafe method of spawnve. + # Please, don't try to optimize this try-except block + # away by assuming that the threading module is always present. + # In the test test/option-j.py we intentionally call SCons with + # a fake threading.py that raises an import exception right away, + # simulating a non-existent package. + def spawnve(mode, file, args, env): + return os.spawnve(mode, file, args, env) + +# The upshot of all this is that, if you are using Python 1.5.2, +# you had better have cmd or command.com in your PATH when you run +# scons. + + +def piped_spawn(sh, escape, cmd, args, env, stdout, stderr): + # There is no direct way to do that in python. What we do + # here should work for most cases: + # In case stdout (stderr) is not redirected to a file, + # we redirect it into a temporary file tmpFileStdout + # (tmpFileStderr) and copy the contents of this file + # to stdout (stderr) given in the argument + if not sh: + sys.stderr.write("scons: Could not find command interpreter, is it in your PATH?\n") + return 127 + else: + # one temporary file for stdout and stderr + tmpFileStdout = os.path.normpath(tempfile.mktemp()) + tmpFileStderr = os.path.normpath(tempfile.mktemp()) + + # check if output is redirected + stdoutRedirected = 0 + stderrRedirected = 0 + for arg in args: + # are there more possibilities to redirect stdout ? + if arg.find( ">", 0, 1 ) != -1 or arg.find( "1>", 0, 2 ) != -1: + stdoutRedirected = 1 + # are there more possibilities to redirect stderr ? + if arg.find( "2>", 0, 2 ) != -1: + stderrRedirected = 1 + + # redirect output of non-redirected streams to our tempfiles + if stdoutRedirected == 0: + args.append(">" + str(tmpFileStdout)) + if stderrRedirected == 0: + args.append("2>" + str(tmpFileStderr)) + + # actually do the spawn + try: + args = [sh, '/C', escape(' '.join(args)) ] + ret = spawnve(os.P_WAIT, sh, args, env) + except OSError as e: + # catch any error + try: + ret = exitvalmap[e.errno] + except KeyError: + sys.stderr.write("scons: unknown OSError exception code %d - %s: %s\n" % (e.errno, cmd, e.strerror)) + if stderr is not None: + stderr.write("scons: %s: %s\n" % (cmd, e.strerror)) + # copy child output from tempfiles to our streams + # and do clean up stuff + if stdout is not None and stdoutRedirected == 0: + try: + stdout.write(open( tmpFileStdout, "r" ).read()) + os.remove( tmpFileStdout ) + except (IOError, OSError): + pass + + if stderr is not None and stderrRedirected == 0: + try: + stderr.write(open( tmpFileStderr, "r" ).read()) + os.remove( tmpFileStderr ) + except (IOError, OSError): + pass + return ret + + +def exec_spawn(l, env): + try: + result = spawnve(os.P_WAIT, l[0], l, env) + except (OSError, EnvironmentError) as e: + try: + result = exitvalmap[e.errno] + sys.stderr.write("scons: %s: %s\n" % (l[0], e.strerror)) + except KeyError: + result = 127 + if len(l) > 2: + if len(l[2]) < 1000: + command = ' '.join(l[0:3]) + else: + command = l[0] + else: + command = l[0] + sys.stderr.write("scons: unknown OSError exception code %d - '%s': %s\n" % (e.errno, command, e.strerror)) + return result + + +def spawn(sh, escape, cmd, args, env): + if not sh: + sys.stderr.write("scons: Could not find command interpreter, is it in your PATH?\n") + return 127 + return exec_spawn([sh, '/C', escape(' '.join(args))], env) + +# Windows does not allow special characters in file names anyway, so no +# need for a complex escape function, we will just quote the arg, except +# that "cmd /c" requires that if an argument ends with a backslash it +# needs to be escaped so as not to interfere with closing double quote +# that we add. +def escape(x): + if x[-1] == '\\': + x = x + '\\' + return '"' + x + '"' + +# Get the windows system directory name +_system_root = None + + +def get_system_root(): + global _system_root + if _system_root is not None: + return _system_root + + # A resonable default if we can't read the registry + val = os.environ.get('SystemRoot', "C:\\WINDOWS") + + if SCons.Util.can_read_reg: + try: + # Look for Windows NT system root + k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE, + 'Software\\Microsoft\\Windows NT\\CurrentVersion') + val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot') + except SCons.Util.RegError: + try: + # Okay, try the Windows 9x system root + k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE, + 'Software\\Microsoft\\Windows\\CurrentVersion') + val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot') + except KeyboardInterrupt: + raise + except: + pass + + # Ensure system root is a string and not unicode + # (This only matters for py27 were unicode in env passed to POpen fails) + val = str(val) + _system_root = val + return val + + +def get_program_files_dir(): + """ + Get the location of the program files directory + Returns + ------- + + """ + # Now see if we can look in the registry... + val = '' + if SCons.Util.can_read_reg: + try: + # Look for Windows Program Files directory + k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE, + 'Software\\Microsoft\\Windows\\CurrentVersion') + val, tok = SCons.Util.RegQueryValueEx(k, 'ProgramFilesDir') + except SCons.Util.RegError: + val = '' + pass + + if val == '': + # A reasonable default if we can't read the registry + # (Actually, it's pretty reasonable even if we can :-) + val = os.path.join(os.path.dirname(get_system_root()),"Program Files") + + return val + + +class ArchDefinition(object): + """ + Determine which windows CPU were running on. + A class for defining architecture-specific settings and logic. + """ + def __init__(self, arch, synonyms=[]): + self.arch = arch + self.synonyms = synonyms + +SupportedArchitectureList = [ + ArchDefinition( + 'x86', + ['i386', 'i486', 'i586', 'i686'], + ), + + ArchDefinition( + 'x86_64', + ['AMD64', 'amd64', 'em64t', 'EM64T', 'x86_64'], + ), + + ArchDefinition( + 'ia64', + ['IA64'], + ), +] + +SupportedArchitectureMap = {} +for a in SupportedArchitectureList: + SupportedArchitectureMap[a.arch] = a + for s in a.synonyms: + SupportedArchitectureMap[s] = a + + +def get_architecture(arch=None): + """Returns the definition for the specified architecture string. + + If no string is specified, the system default is returned (as defined + by the PROCESSOR_ARCHITEW6432 or PROCESSOR_ARCHITECTURE environment + variables). + """ + if arch is None: + arch = os.environ.get('PROCESSOR_ARCHITEW6432') + if not arch: + arch = os.environ.get('PROCESSOR_ARCHITECTURE') + return SupportedArchitectureMap.get(arch, ArchDefinition('', [''])) + + +def generate(env): + # Attempt to find cmd.exe (for WinNT/2k/XP) or + # command.com for Win9x + cmd_interp = '' + # First see if we can look in the registry... + if SCons.Util.can_read_reg: + try: + # Look for Windows NT system root + k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE, + 'Software\\Microsoft\\Windows NT\\CurrentVersion') + val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot') + cmd_interp = os.path.join(val, 'System32\\cmd.exe') + except SCons.Util.RegError: + try: + # Okay, try the Windows 9x system root + k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE, + 'Software\\Microsoft\\Windows\\CurrentVersion') + val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot') + cmd_interp = os.path.join(val, 'command.com') + except KeyboardInterrupt: + raise + except: + pass + + # For the special case of not having access to the registry, we + # use a temporary path and pathext to attempt to find the command + # interpreter. If we fail, we try to find the interpreter through + # the env's PATH. The problem with that is that it might not + # contain an ENV and a PATH. + if not cmd_interp: + systemroot = get_system_root() + tmp_path = systemroot + os.pathsep + \ + os.path.join(systemroot,'System32') + tmp_pathext = '.com;.exe;.bat;.cmd' + if 'PATHEXT' in os.environ: + tmp_pathext = os.environ['PATHEXT'] + cmd_interp = SCons.Util.WhereIs('cmd', tmp_path, tmp_pathext) + if not cmd_interp: + cmd_interp = SCons.Util.WhereIs('command', tmp_path, tmp_pathext) + + if not cmd_interp: + cmd_interp = env.Detect('cmd') + if not cmd_interp: + cmd_interp = env.Detect('command') + + if 'ENV' not in env: + env['ENV'] = {} + + # Import things from the external environment to the construction + # environment's ENV. This is a potential slippery slope, because we + # *don't* want to make builds dependent on the user's environment by + # default. We're doing this for SystemRoot, though, because it's + # needed for anything that uses sockets, and seldom changes, and + # for SystemDrive because it's related. + # + # Weigh the impact carefully before adding other variables to this list. + import_env = ['SystemDrive', 'SystemRoot', 'TEMP', 'TMP' ] + for var in import_env: + v = os.environ.get(var) + if v: + env['ENV'][var] = v + + if 'COMSPEC' not in env['ENV']: + v = os.environ.get("COMSPEC") + if v: + env['ENV']['COMSPEC'] = v + + env.AppendENVPath('PATH', get_system_root() + '\\System32') + + env['ENV']['PATHEXT'] = '.COM;.EXE;.BAT;.CMD' + env['OBJPREFIX'] = '' + env['OBJSUFFIX'] = '.obj' + env['SHOBJPREFIX'] = '$OBJPREFIX' + env['SHOBJSUFFIX'] = '$OBJSUFFIX' + env['PROGPREFIX'] = '' + env['PROGSUFFIX'] = '.exe' + env['LIBPREFIX'] = '' + env['LIBSUFFIX'] = '.lib' + env['SHLIBPREFIX'] = '' + env['SHLIBSUFFIX'] = '.dll' + env['LIBPREFIXES'] = [ '$LIBPREFIX' ] + env['LIBSUFFIXES'] = [ '$LIBSUFFIX' ] + env['PSPAWN'] = piped_spawn + env['SPAWN'] = spawn + env['SHELL'] = cmd_interp + env['TEMPFILE'] = TempFileMunge + env['TEMPFILEPREFIX'] = '@' + env['MAXLINELENGTH'] = 2048 + env['ESCAPE'] = escape + + env['HOST_OS'] = 'win32' + env['HOST_ARCH'] = get_architecture().arch + + if enable_virtualenv and not ignore_virtualenv: + ImportVirtualenv(env) + + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/SConf.py b/tools/scons/scons-local-3.0.5/SCons/SConf.py new file mode 100755 index 0000000000..66592d404d --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/SConf.py @@ -0,0 +1,1095 @@ +"""SCons.SConf + +Autoconf-like configuration support. + +In other words, SConf allows to run tests on the build machine to detect +capabilities of system and do some things based on result: generate config +files, header files for C/C++, update variables in environment. + +Tests on the build system can detect if compiler sees header files, if +libraries are installed, if some command line options are supported etc. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +from __future__ import print_function + +__revision__ = "src/engine/SCons/SConf.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.compat + +import io +import os +import re +import sys +import traceback + +import SCons.Action +import SCons.Builder +import SCons.Errors +import SCons.Job +import SCons.Node.FS +import SCons.Taskmaster +import SCons.Util +import SCons.Warnings +import SCons.Conftest + +from SCons.Debug import Trace +from SCons.Node import DeciderNeedsNode + +# Turn off the Conftest error logging +SCons.Conftest.LogInputFiles = 0 +SCons.Conftest.LogErrorMessages = 0 + +# Set +build_type = None +build_types = ['clean', 'help'] + +def SetBuildType(type): + global build_type + build_type = type + +# to be set, if we are in dry-run mode +dryrun = 0 + +AUTO=0 # use SCons dependency scanning for up-to-date checks +FORCE=1 # force all tests to be rebuilt +CACHE=2 # force all tests to be taken from cache (raise an error, if necessary) +cache_mode = AUTO + +def SetCacheMode(mode): + """Set the Configure cache mode. mode must be one of "auto", "force", + or "cache".""" + global cache_mode + if mode == "auto": + cache_mode = AUTO + elif mode == "force": + cache_mode = FORCE + elif mode == "cache": + cache_mode = CACHE + else: + raise ValueError("SCons.SConf.SetCacheMode: Unknown mode " + mode) + +progress_display = SCons.Util.display # will be overwritten by SCons.Script +def SetProgressDisplay(display): + """Set the progress display to use (called from SCons.Script)""" + global progress_display + progress_display = display + +SConfFS = None + +_ac_build_counter = 0 # incremented, whenever TryBuild is called +_ac_config_logs = {} # all config.log files created in this build +_ac_config_hs = {} # all config.h files created in this build +sconf_global = None # current sconf object + +def _createConfigH(target, source, env): + t = open(str(target[0]), "w") + defname = re.sub('[^A-Za-z0-9_]', '_', str(target[0]).upper()) + t.write("""#ifndef %(DEFNAME)s_SEEN +#define %(DEFNAME)s_SEEN + +""" % {'DEFNAME' : defname}) + t.write(source[0].get_contents().decode()) + t.write(""" +#endif /* %(DEFNAME)s_SEEN */ +""" % {'DEFNAME' : defname}) + t.close() + +def _stringConfigH(target, source, env): + return "scons: Configure: creating " + str(target[0]) + + +def NeedConfigHBuilder(): + if len(_ac_config_hs) == 0: + return False + else: + return True + +def CreateConfigHBuilder(env): + """Called if necessary just before the building targets phase begins.""" + action = SCons.Action.Action(_createConfigH, + _stringConfigH) + sconfigHBld = SCons.Builder.Builder(action=action) + env.Append( BUILDERS={'SConfigHBuilder':sconfigHBld} ) + for k in list(_ac_config_hs.keys()): + env.SConfigHBuilder(k, env.Value(_ac_config_hs[k])) + + +class SConfWarning(SCons.Warnings.Warning): + pass +SCons.Warnings.enableWarningClass(SConfWarning) + +# some error definitions +class SConfError(SCons.Errors.UserError): + def __init__(self,msg): + SCons.Errors.UserError.__init__(self,msg) + +class ConfigureDryRunError(SConfError): + """Raised when a file or directory needs to be updated during a Configure + process, but the user requested a dry-run""" + def __init__(self,target): + if not isinstance(target, SCons.Node.FS.File): + msg = 'Cannot create configure directory "%s" within a dry-run.' % str(target) + else: + msg = 'Cannot update configure test "%s" within a dry-run.' % str(target) + SConfError.__init__(self,msg) + +class ConfigureCacheError(SConfError): + """Raised when a use explicitely requested the cache feature, but the test + is run the first time.""" + def __init__(self,target): + SConfError.__init__(self, '"%s" is not yet built and cache is forced.' % str(target)) + +# define actions for building text files +def _createSource( target, source, env ): + fd = open(str(target[0]), "w") + fd.write(source[0].get_contents().decode()) + fd.close() +def _stringSource( target, source, env ): + return (str(target[0]) + ' <-\n |' + + source[0].get_contents().decode().replace( '\n', "\n |" ) ) + +class SConfBuildInfo(SCons.Node.FS.FileBuildInfo): + """ + Special build info for targets of configure tests. Additional members + are result (did the builder succeed last time?) and string, which + contains messages of the original build phase. + """ + __slots__ = ('result', 'string') + + def __init__(self): + self.result = None # -> 0/None -> no error, != 0 error + self.string = None # the stdout / stderr output when building the target + + def set_build_result(self, result, string): + self.result = result + self.string = string + + +class Streamer(object): + """ + 'Sniffer' for a file-like writable object. Similar to the unix tool tee. + """ + def __init__(self, orig): + self.orig = orig + self.s = io.StringIO() + + def write(self, str): + if self.orig: + self.orig.write(str) + try: + self.s.write(str) + except TypeError as e: + # "unicode argument expected" bug in IOStream (python 2.x) + self.s.write(str.decode()) + + def writelines(self, lines): + for l in lines: + self.write(l + '\n') + + def getvalue(self): + """ + Return everything written to orig since the Streamer was created. + """ + return self.s.getvalue() + + def flush(self): + if self.orig: + self.orig.flush() + self.s.flush() + + +class SConfBuildTask(SCons.Taskmaster.AlwaysTask): + """ + This is almost the same as SCons.Script.BuildTask. Handles SConfErrors + correctly and knows about the current cache_mode. + """ + def display(self, message): + if sconf_global.logstream: + sconf_global.logstream.write("scons: Configure: " + message + "\n") + + def display_cached_string(self, bi): + """ + Logs the original builder messages, given the SConfBuildInfo instance + bi. + """ + if not isinstance(bi, SConfBuildInfo): + SCons.Warnings.warn(SConfWarning, + "The stored build information has an unexpected class: %s" % bi.__class__) + else: + self.display("The original builder output was:\n" + + (" |" + str(bi.string)).replace("\n", "\n |")) + + def failed(self): + # check, if the reason was a ConfigureDryRunError or a + # ConfigureCacheError and if yes, reraise the exception + exc_type = self.exc_info()[0] + if issubclass(exc_type, SConfError): + raise + elif issubclass(exc_type, SCons.Errors.BuildError): + # we ignore Build Errors (occurs, when a test doesn't pass) + # Clear the exception to prevent the contained traceback + # to build a reference cycle. + self.exc_clear() + else: + self.display('Caught exception while building "%s":\n' % + self.targets[0]) + sys.excepthook(*self.exc_info()) + return SCons.Taskmaster.Task.failed(self) + + def collect_node_states(self): + # returns (is_up_to_date, cached_error, cachable) + # where is_up_to_date is 1, if the node(s) are up_to_date + # cached_error is 1, if the node(s) are up_to_date, but the + # build will fail + # cachable is 0, if some nodes are not in our cache + T = 0 + changed = False + cached_error = False + cachable = True + for t in self.targets: + if T: Trace('%s' % (t)) + bi = t.get_stored_info().binfo + if isinstance(bi, SConfBuildInfo): + if T: Trace(': SConfBuildInfo') + if cache_mode == CACHE: + t.set_state(SCons.Node.up_to_date) + if T: Trace(': set_state(up_to-date)') + else: + if T: Trace(': get_state() %s' % t.get_state()) + if T: Trace(': changed() %s' % t.changed()) + if (t.get_state() != SCons.Node.up_to_date and t.changed()): + changed = True + if T: Trace(': changed %s' % changed) + cached_error = cached_error or bi.result + else: + if T: Trace(': else') + # the node hasn't been built in a SConf context or doesn't + # exist + cachable = False + changed = ( t.get_state() != SCons.Node.up_to_date ) + if T: Trace(': changed %s' % changed) + if T: Trace('\n') + return (not changed, cached_error, cachable) + + def execute(self): + if not self.targets[0].has_builder(): + return + + sconf = sconf_global + + is_up_to_date, cached_error, cachable = self.collect_node_states() + + if cache_mode == CACHE and not cachable: + raise ConfigureCacheError(self.targets[0]) + elif cache_mode == FORCE: + is_up_to_date = 0 + + if cached_error and is_up_to_date: + self.display("Building \"%s\" failed in a previous run and all " + "its sources are up to date." % str(self.targets[0])) + binfo = self.targets[0].get_stored_info().binfo + self.display_cached_string(binfo) + raise SCons.Errors.BuildError # will be 'caught' in self.failed + elif is_up_to_date: + self.display("\"%s\" is up to date." % str(self.targets[0])) + binfo = self.targets[0].get_stored_info().binfo + self.display_cached_string(binfo) + elif dryrun: + raise ConfigureDryRunError(self.targets[0]) + else: + # note stdout and stderr are the same here + s = sys.stdout = sys.stderr = Streamer(sys.stdout) + try: + env = self.targets[0].get_build_env() + env['PSTDOUT'] = env['PSTDERR'] = s + try: + sconf.cached = 0 + self.targets[0].build() + finally: + sys.stdout = sys.stderr = env['PSTDOUT'] = \ + env['PSTDERR'] = sconf.logstream + except KeyboardInterrupt: + raise + except SystemExit: + exc_value = sys.exc_info()[1] + raise SCons.Errors.ExplicitExit(self.targets[0],exc_value.code) + except Exception as e: + for t in self.targets: + binfo = SConfBuildInfo() + binfo.merge(t.get_binfo()) + binfo.set_build_result(1, s.getvalue()) + sconsign_entry = SCons.SConsign.SConsignEntry() + sconsign_entry.binfo = binfo + #sconsign_entry.ninfo = self.get_ninfo() + # We'd like to do this as follows: + # t.store_info(binfo) + # However, we need to store it as an SConfBuildInfo + # object, and store_info() will turn it into a + # regular FileNodeInfo if the target is itself a + # regular File. + sconsign = t.dir.sconsign() + sconsign.set_entry(t.name, sconsign_entry) + sconsign.merge() + raise e + else: + for t in self.targets: + binfo = SConfBuildInfo() + binfo.merge(t.get_binfo()) + binfo.set_build_result(0, s.getvalue()) + sconsign_entry = SCons.SConsign.SConsignEntry() + sconsign_entry.binfo = binfo + #sconsign_entry.ninfo = self.get_ninfo() + # We'd like to do this as follows: + # t.store_info(binfo) + # However, we need to store it as an SConfBuildInfo + # object, and store_info() will turn it into a + # regular FileNodeInfo if the target is itself a + # regular File. + sconsign = t.dir.sconsign() + sconsign.set_entry(t.name, sconsign_entry) + sconsign.merge() + +class SConfBase(object): + """This is simply a class to represent a configure context. After + creating a SConf object, you can call any tests. After finished with your + tests, be sure to call the Finish() method, which returns the modified + environment. + Some words about caching: In most cases, it is not necessary to cache + Test results explicitly. Instead, we use the scons dependency checking + mechanism. For example, if one wants to compile a test program + (SConf.TryLink), the compiler is only called, if the program dependencies + have changed. However, if the program could not be compiled in a former + SConf run, we need to explicitly cache this error. + """ + + def __init__(self, env, custom_tests = {}, conf_dir='$CONFIGUREDIR', + log_file='$CONFIGURELOG', config_h = None, _depth = 0): + """Constructor. Pass additional tests in the custom_tests-dictionary, + e.g. custom_tests={'CheckPrivate':MyPrivateTest}, where MyPrivateTest + defines a custom test. + Note also the conf_dir and log_file arguments (you may want to + build tests in the VariantDir, not in the SourceDir) + """ + global SConfFS + + # Now create isolated override so setting source_decider doesn't affect parent Environment + if cache_mode == FORCE: + self.original_env = env + self.env = env.Clone() + + # Set up the Decider() to force rebuilds by saying + # that every source has changed. Note that we still + # call the environment's underlying source decider so + # that the correct .sconsign info will get calculated + # and keep the build state consistent. + def force_build(dependency, target, prev_ni, + env_decider=env.decide_source, + node=None): + try: + env_decider(dependency, target, prev_ni) + except DeciderNeedsNode as e: + e.decider(target, prev_ni, node=target) + except Exception as e: + raise e + return True + + if self.env.decide_source.__code__ is not force_build.__code__: + self.env.Decider(force_build) + + else: + self.env = env + + # print("Override env:%s"%env) + + if not SConfFS: + SConfFS = SCons.Node.FS.default_fs or \ + SCons.Node.FS.FS(env.fs.pathTop) + if sconf_global is not None: + raise SCons.Errors.UserError + + if log_file is not None: + log_file = SConfFS.File(env.subst(log_file)) + self.logfile = log_file + self.logstream = None + self.lastTarget = None + self.depth = _depth + self.cached = 0 # will be set, if all test results are cached + + # add default tests + default_tests = { + 'CheckCC' : CheckCC, + 'CheckCXX' : CheckCXX, + 'CheckSHCC' : CheckSHCC, + 'CheckSHCXX' : CheckSHCXX, + 'CheckFunc' : CheckFunc, + 'CheckType' : CheckType, + 'CheckTypeSize' : CheckTypeSize, + 'CheckDeclaration' : CheckDeclaration, + 'CheckHeader' : CheckHeader, + 'CheckCHeader' : CheckCHeader, + 'CheckCXXHeader' : CheckCXXHeader, + 'CheckLib' : CheckLib, + 'CheckLibWithHeader' : CheckLibWithHeader, + 'CheckProg' : CheckProg, + } + self.AddTests(default_tests) + self.AddTests(custom_tests) + self.confdir = SConfFS.Dir(env.subst(conf_dir)) + if config_h is not None: + config_h = SConfFS.File(config_h) + self.config_h = config_h + self._startup() + + def Finish(self): + """Call this method after finished with your tests: + env = sconf.Finish() + """ + self._shutdown() + + return self.env + + def Define(self, name, value = None, comment = None): + """ + Define a pre processor symbol name, with the optional given value in the + current config header. + + If value is None (default), then #define name is written. If value is not + none, then #define name value is written. + + comment is a string which will be put as a C comment in the header, to explain the meaning of the value + (appropriate C comments will be added automatically). + """ + lines = [] + if comment: + comment_str = "/* %s */" % comment + lines.append(comment_str) + + if value is not None: + define_str = "#define %s %s" % (name, value) + else: + define_str = "#define %s" % name + lines.append(define_str) + lines.append('') + + self.config_h_text = self.config_h_text + '\n'.join(lines) + + def BuildNodes(self, nodes): + """ + Tries to build the given nodes immediately. Returns 1 on success, + 0 on error. + """ + if self.logstream is not None: + # override stdout / stderr to write in log file + oldStdout = sys.stdout + sys.stdout = self.logstream + oldStderr = sys.stderr + sys.stderr = self.logstream + + # the engine assumes the current path is the SConstruct directory ... + old_fs_dir = SConfFS.getcwd() + old_os_dir = os.getcwd() + SConfFS.chdir(SConfFS.Top, change_os_dir=1) + + # Because we take responsibility here for writing out our + # own .sconsign info (see SConfBuildTask.execute(), above), + # we override the store_info() method with a null place-holder + # so we really control how it gets written. + for n in nodes: + n.store_info = 0 + if not hasattr(n, 'attributes'): + n.attributes = SCons.Node.Node.Attrs() + n.attributes.keep_targetinfo = 1 + + if True: + # Some checkers have intermediate files (for example anything that compiles a c file into a program to run + # Those files need to be set to not release their target info, otherwise taskmaster will throw a + # Nonetype not callable + for c in n.children(scan=False): + # Keep debug code here. + # print("Checking [%s] for builders and then setting keep_targetinfo"%c) + if c.has_builder(): + n.store_info = 0 + if not hasattr(c, 'attributes'): + c.attributes = SCons.Node.Node.Attrs() + c.attributes.keep_targetinfo = 1 + # pass + + ret = 1 + + try: + # ToDo: use user options for calc + save_max_drift = SConfFS.get_max_drift() + SConfFS.set_max_drift(0) + tm = SCons.Taskmaster.Taskmaster(nodes, SConfBuildTask) + # we don't want to build tests in parallel + jobs = SCons.Job.Jobs(1, tm ) + jobs.run() + for n in nodes: + state = n.get_state() + if (state != SCons.Node.executed and + state != SCons.Node.up_to_date): + # the node could not be built. we return 0 in this case + ret = 0 + finally: + SConfFS.set_max_drift(save_max_drift) + os.chdir(old_os_dir) + SConfFS.chdir(old_fs_dir, change_os_dir=0) + if self.logstream is not None: + # restore stdout / stderr + sys.stdout = oldStdout + sys.stderr = oldStderr + return ret + + def pspawn_wrapper(self, sh, escape, cmd, args, env): + """Wrapper function for handling piped spawns. + + This looks to the calling interface (in Action.py) like a "normal" + spawn, but associates the call with the PSPAWN variable from + the construction environment and with the streams to which we + want the output logged. This gets slid into the construction + environment as the SPAWN variable so Action.py doesn't have to + know or care whether it's spawning a piped command or not. + """ + return self.pspawn(sh, escape, cmd, args, env, self.logstream, self.logstream) + + + def TryBuild(self, builder, text = None, extension = ""): + """Low level TryBuild implementation. Normally you don't need to + call that - you can use TryCompile / TryLink / TryRun instead + """ + global _ac_build_counter + + # Make sure we have a PSPAWN value, and save the current + # SPAWN value. + try: + self.pspawn = self.env['PSPAWN'] + except KeyError: + raise SCons.Errors.UserError('Missing PSPAWN construction variable.') + try: + save_spawn = self.env['SPAWN'] + except KeyError: + raise SCons.Errors.UserError('Missing SPAWN construction variable.') + + nodesToBeBuilt = [] + + f = "conftest_" + str(_ac_build_counter) + pref = self.env.subst( builder.builder.prefix ) + suff = self.env.subst( builder.builder.suffix ) + target = self.confdir.File(pref + f + suff) + + try: + # Slide our wrapper into the construction environment as + # the SPAWN function. + self.env['SPAWN'] = self.pspawn_wrapper + sourcetext = self.env.Value(text) + + if text is not None: + textFile = self.confdir.File(f + extension) + textFileNode = self.env.SConfSourceBuilder(target=textFile, + source=sourcetext) + nodesToBeBuilt.extend(textFileNode) + source = textFileNode + else: + source = None + + nodes = builder(target = target, source = source) + if not SCons.Util.is_List(nodes): + nodes = [nodes] + nodesToBeBuilt.extend(nodes) + result = self.BuildNodes(nodesToBeBuilt) + + finally: + self.env['SPAWN'] = save_spawn + + _ac_build_counter = _ac_build_counter + 1 + if result: + self.lastTarget = nodes[0] + else: + self.lastTarget = None + + return result + + def TryAction(self, action, text = None, extension = ""): + """Tries to execute the given action with optional source file + contents and optional source file extension , + Returns the status (0 : failed, 1 : ok) and the contents of the + output file. + """ + builder = SCons.Builder.Builder(action=action) + self.env.Append( BUILDERS = {'SConfActionBuilder' : builder} ) + ok = self.TryBuild(self.env.SConfActionBuilder, text, extension) + del self.env['BUILDERS']['SConfActionBuilder'] + if ok: + outputStr = self.lastTarget.get_text_contents() + return (1, outputStr) + return (0, "") + + def TryCompile( self, text, extension): + """Compiles the program given in text to an env.Object, using extension + as file extension (e.g. '.c'). Returns 1, if compilation was + successful, 0 otherwise. The target is saved in self.lastTarget (for + further processing). + """ + return self.TryBuild(self.env.Object, text, extension) + + def TryLink( self, text, extension ): + """Compiles the program given in text to an executable env.Program, + using extension as file extension (e.g. '.c'). Returns 1, if + compilation was successful, 0 otherwise. The target is saved in + self.lastTarget (for further processing). + """ + return self.TryBuild(self.env.Program, text, extension ) + + def TryRun(self, text, extension ): + """Compiles and runs the program given in text, using extension + as file extension (e.g. '.c'). Returns (1, outputStr) on success, + (0, '') otherwise. The target (a file containing the program's stdout) + is saved in self.lastTarget (for further processing). + """ + ok = self.TryLink(text, extension) + if( ok ): + prog = self.lastTarget + pname = prog.get_internal_path() + output = self.confdir.File(os.path.basename(pname)+'.out') + node = self.env.Command(output, prog, [ [ pname, ">", "${TARGET}"] ]) + ok = self.BuildNodes(node) + if ok: + outputStr = SCons.Util.to_str(output.get_contents()) + return( 1, outputStr) + return (0, "") + + class TestWrapper(object): + """A wrapper around Tests (to ensure sanity)""" + def __init__(self, test, sconf): + self.test = test + self.sconf = sconf + def __call__(self, *args, **kw): + if not self.sconf.active: + raise SCons.Errors.UserError + context = CheckContext(self.sconf) + ret = self.test(context, *args, **kw) + if self.sconf.config_h is not None: + self.sconf.config_h_text = self.sconf.config_h_text + context.config_h + context.Result("error: no result") + return ret + + def AddTest(self, test_name, test_instance): + """Adds test_class to this SConf instance. It can be called with + self.test_name(...)""" + setattr(self, test_name, SConfBase.TestWrapper(test_instance, self)) + + def AddTests(self, tests): + """Adds all the tests given in the tests dictionary to this SConf + instance + """ + for name in list(tests.keys()): + self.AddTest(name, tests[name]) + + def _createDir( self, node ): + dirName = str(node) + if dryrun: + if not os.path.isdir( dirName ): + raise ConfigureDryRunError(dirName) + else: + if not os.path.isdir( dirName ): + os.makedirs( dirName ) + + def _startup(self): + """Private method. Set up logstream, and set the environment + variables necessary for a piped build + """ + global _ac_config_logs + global sconf_global + global SConfFS + + self.lastEnvFs = self.env.fs + self.env.fs = SConfFS + self._createDir(self.confdir) + self.confdir.up().add_ignore( [self.confdir] ) + + if self.logfile is not None and not dryrun: + # truncate logfile, if SConf.Configure is called for the first time + # in a build + if self.logfile in _ac_config_logs: + log_mode = "a" + else: + _ac_config_logs[self.logfile] = None + log_mode = "w" + fp = open(str(self.logfile), log_mode) + self.logstream = SCons.Util.Unbuffered(fp) + # logfile may stay in a build directory, so we tell + # the build system not to override it with a eventually + # existing file with the same name in the source directory + self.logfile.dir.add_ignore( [self.logfile] ) + + tb = traceback.extract_stack()[-3-self.depth] + old_fs_dir = SConfFS.getcwd() + SConfFS.chdir(SConfFS.Top, change_os_dir=0) + self.logstream.write('file %s,line %d:\n\tConfigure(confdir = %s)\n' % + (tb[0], tb[1], str(self.confdir)) ) + SConfFS.chdir(old_fs_dir) + else: + self.logstream = None + # we use a special builder to create source files from TEXT + action = SCons.Action.Action(_createSource, + _stringSource) + sconfSrcBld = SCons.Builder.Builder(action=action) + self.env.Append( BUILDERS={'SConfSourceBuilder':sconfSrcBld} ) + self.config_h_text = _ac_config_hs.get(self.config_h, "") + self.active = 1 + # only one SConf instance should be active at a time ... + sconf_global = self + + def _shutdown(self): + """Private method. Reset to non-piped spawn""" + global sconf_global, _ac_config_hs + + if not self.active: + raise SCons.Errors.UserError("Finish may be called only once!") + if self.logstream is not None and not dryrun: + self.logstream.write("\n") + self.logstream.close() + self.logstream = None + + # Now reset the decider if we changed it due to --config=force + # We saved original Environment passed in and cloned it to isolate + # it from being changed. + if cache_mode == FORCE: + self.env.Decider(self.original_env.decide_source) + + # remove the SConfSourceBuilder from the environment + blds = self.env['BUILDERS'] + del blds['SConfSourceBuilder'] + self.env.Replace( BUILDERS=blds ) + + self.active = 0 + sconf_global = None + if not self.config_h is None: + _ac_config_hs[self.config_h] = self.config_h_text + self.env.fs = self.lastEnvFs + +class CheckContext(object): + """Provides a context for configure tests. Defines how a test writes to the + screen and log file. + + A typical test is just a callable with an instance of CheckContext as + first argument: + + def CheckCustom(context, ...): + context.Message('Checking my weird test ... ') + ret = myWeirdTestFunction(...) + context.Result(ret) + + Often, myWeirdTestFunction will be one of + context.TryCompile/context.TryLink/context.TryRun. The results of + those are cached, for they are only rebuild, if the dependencies have + changed. + """ + + def __init__(self, sconf): + """Constructor. Pass the corresponding SConf instance.""" + self.sconf = sconf + self.did_show_result = 0 + + # for Conftest.py: + self.vardict = {} + self.havedict = {} + self.headerfilename = None + self.config_h = "" # config_h text will be stored here + # we don't regenerate the config.h file after each test. That means, + # that tests won't be able to include the config.h file, and so + # they can't do an #ifdef HAVE_XXX_H. This shouldn't be a major + # issue, though. If it turns out, that we need to include config.h + # in tests, we must ensure, that the dependencies are worked out + # correctly. Note that we can't use Conftest.py's support for config.h, + # cause we will need to specify a builder for the config.h file ... + + def Message(self, text): + """Inform about what we are doing right now, e.g. + 'Checking for SOMETHING ... ' + """ + self.Display(text) + self.sconf.cached = 1 + self.did_show_result = 0 + + def Result(self, res): + """Inform about the result of the test. If res is not a string, displays + 'yes' or 'no' depending on whether res is evaluated as true or false. + The result is only displayed when self.did_show_result is not set. + """ + if isinstance(res, str): + text = res + elif res: + text = "yes" + else: + text = "no" + + if self.did_show_result == 0: + # Didn't show result yet, do it now. + self.Display(text + "\n") + self.did_show_result = 1 + + def TryBuild(self, *args, **kw): + return self.sconf.TryBuild(*args, **kw) + + def TryAction(self, *args, **kw): + return self.sconf.TryAction(*args, **kw) + + def TryCompile(self, *args, **kw): + return self.sconf.TryCompile(*args, **kw) + + def TryLink(self, *args, **kw): + return self.sconf.TryLink(*args, **kw) + + def TryRun(self, *args, **kw): + return self.sconf.TryRun(*args, **kw) + + def __getattr__( self, attr ): + if( attr == 'env' ): + return self.sconf.env + elif( attr == 'lastTarget' ): + return self.sconf.lastTarget + else: + raise AttributeError("CheckContext instance has no attribute '%s'" % attr) + + #### Stuff used by Conftest.py (look there for explanations). + + def BuildProg(self, text, ext): + self.sconf.cached = 1 + # TODO: should use self.vardict for $CC, $CPPFLAGS, etc. + return not self.TryBuild(self.env.Program, text, ext) + + def CompileProg(self, text, ext): + self.sconf.cached = 1 + # TODO: should use self.vardict for $CC, $CPPFLAGS, etc. + return not self.TryBuild(self.env.Object, text, ext) + + def CompileSharedObject(self, text, ext): + self.sconf.cached = 1 + # TODO: should use self.vardict for $SHCC, $CPPFLAGS, etc. + return not self.TryBuild(self.env.SharedObject, text, ext) + + def RunProg(self, text, ext): + self.sconf.cached = 1 + # TODO: should use self.vardict for $CC, $CPPFLAGS, etc. + st, out = self.TryRun(text, ext) + return not st, out + + def AppendLIBS(self, lib_name_list): + oldLIBS = self.env.get( 'LIBS', [] ) + self.env.Append(LIBS = lib_name_list) + return oldLIBS + + def PrependLIBS(self, lib_name_list): + oldLIBS = self.env.get( 'LIBS', [] ) + self.env.Prepend(LIBS = lib_name_list) + return oldLIBS + + def SetLIBS(self, val): + oldLIBS = self.env.get( 'LIBS', [] ) + self.env.Replace(LIBS = val) + return oldLIBS + + def Display(self, msg): + if self.sconf.cached: + # We assume that Display is called twice for each test here + # once for the Checking for ... message and once for the result. + # The self.sconf.cached flag can only be set between those calls + msg = "(cached) " + msg + self.sconf.cached = 0 + progress_display(msg, append_newline=0) + self.Log("scons: Configure: " + msg + "\n") + + def Log(self, msg): + if self.sconf.logstream is not None: + self.sconf.logstream.write(msg) + + #### End of stuff used by Conftest.py. + + +def SConf(*args, **kw): + if kw.get(build_type, True): + kw['_depth'] = kw.get('_depth', 0) + 1 + for bt in build_types: + try: + del kw[bt] + except KeyError: + pass + return SConfBase(*args, **kw) + else: + return SCons.Util.Null() + + +def CheckFunc(context, function_name, header = None, language = None): + res = SCons.Conftest.CheckFunc(context, function_name, header = header, language = language) + context.did_show_result = 1 + return not res + +def CheckType(context, type_name, includes = "", language = None): + res = SCons.Conftest.CheckType(context, type_name, + header = includes, language = language) + context.did_show_result = 1 + return not res + +def CheckTypeSize(context, type_name, includes = "", language = None, expect = None): + res = SCons.Conftest.CheckTypeSize(context, type_name, + header = includes, language = language, + expect = expect) + context.did_show_result = 1 + return res + +def CheckDeclaration(context, declaration, includes = "", language = None): + res = SCons.Conftest.CheckDeclaration(context, declaration, + includes = includes, + language = language) + context.did_show_result = 1 + return not res + +def createIncludesFromHeaders(headers, leaveLast, include_quotes = '""'): + # used by CheckHeader and CheckLibWithHeader to produce C - #include + # statements from the specified header (list) + if not SCons.Util.is_List(headers): + headers = [headers] + l = [] + if leaveLast: + lastHeader = headers[-1] + headers = headers[:-1] + else: + lastHeader = None + for s in headers: + l.append("#include %s%s%s\n" + % (include_quotes[0], s, include_quotes[1])) + return ''.join(l), lastHeader + +def CheckHeader(context, header, include_quotes = '<>', language = None): + """ + A test for a C or C++ header file. + """ + prog_prefix, hdr_to_check = \ + createIncludesFromHeaders(header, 1, include_quotes) + res = SCons.Conftest.CheckHeader(context, hdr_to_check, prog_prefix, + language = language, + include_quotes = include_quotes) + context.did_show_result = 1 + return not res + +def CheckCC(context): + res = SCons.Conftest.CheckCC(context) + context.did_show_result = 1 + return not res + +def CheckCXX(context): + res = SCons.Conftest.CheckCXX(context) + context.did_show_result = 1 + return not res + +def CheckSHCC(context): + res = SCons.Conftest.CheckSHCC(context) + context.did_show_result = 1 + return not res + +def CheckSHCXX(context): + res = SCons.Conftest.CheckSHCXX(context) + context.did_show_result = 1 + return not res + +# Bram: Make this function obsolete? CheckHeader() is more generic. + +def CheckCHeader(context, header, include_quotes = '""'): + """ + A test for a C header file. + """ + return CheckHeader(context, header, include_quotes, language = "C") + + +# Bram: Make this function obsolete? CheckHeader() is more generic. + +def CheckCXXHeader(context, header, include_quotes = '""'): + """ + A test for a C++ header file. + """ + return CheckHeader(context, header, include_quotes, language = "C++") + + +def CheckLib(context, library = None, symbol = "main", + header = None, language = None, autoadd = 1): + """ + A test for a library. See also CheckLibWithHeader. + Note that library may also be None to test whether the given symbol + compiles without flags. + """ + + if not library: + library = [None] + + if not SCons.Util.is_List(library): + library = [library] + + # ToDo: accept path for the library + res = SCons.Conftest.CheckLib(context, library, symbol, header = header, + language = language, autoadd = autoadd) + context.did_show_result = 1 + return not res + +# XXX +# Bram: Can only include one header and can't use #ifdef HAVE_HEADER_H. + +def CheckLibWithHeader(context, libs, header, language, + call = None, autoadd = 1): + # ToDo: accept path for library. Support system header files. + """ + Another (more sophisticated) test for a library. + Checks, if library and header is available for language (may be 'C' + or 'CXX'). Call maybe be a valid expression _with_ a trailing ';'. + As in CheckLib, we support library=None, to test if the call compiles + without extra link flags. + """ + prog_prefix, dummy = \ + createIncludesFromHeaders(header, 0) + if libs == []: + libs = [None] + + if not SCons.Util.is_List(libs): + libs = [libs] + + res = SCons.Conftest.CheckLib(context, libs, None, prog_prefix, + call = call, language = language, autoadd = autoadd) + context.did_show_result = 1 + return not res + +def CheckProg(context, prog_name): + """Simple check if a program exists in the path. Returns the path + for the application, or None if not found. + """ + res = SCons.Conftest.CheckProg(context, prog_name) + context.did_show_result = 1 + return res + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/SConsign.py b/tools/scons/scons-local-3.0.5/SCons/SConsign.py new file mode 100755 index 0000000000..1fec6a09c0 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/SConsign.py @@ -0,0 +1,427 @@ +"""SCons.SConsign + +Writing and reading information to the .sconsign file or files. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +from __future__ import print_function + +__revision__ = "src/engine/SCons/SConsign.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.compat + +import os +import pickle + +import SCons.dblite +import SCons.Warnings + +from SCons.compat import PICKLE_PROTOCOL + + +def corrupt_dblite_warning(filename): + SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning, + "Ignoring corrupt .sconsign file: %s"%filename) + +SCons.dblite.ignore_corrupt_dbfiles = 1 +SCons.dblite.corruption_warning = corrupt_dblite_warning + +# XXX Get rid of the global array so this becomes re-entrant. +sig_files = [] + +# Info for the database SConsign implementation (now the default): +# "DataBase" is a dictionary that maps top-level SConstruct directories +# to open database handles. +# "DB_Module" is the Python database module to create the handles. +# "DB_Name" is the base name of the database file (minus any +# extension the underlying DB module will add). +DataBase = {} +DB_Module = SCons.dblite +DB_Name = ".sconsign" +DB_sync_list = [] + + +def Get_DataBase(dir): + global DataBase, DB_Module, DB_Name + top = dir.fs.Top + if not os.path.isabs(DB_Name) and top.repositories: + mode = "c" + for d in [top] + top.repositories: + if dir.is_under(d): + try: + return DataBase[d], mode + except KeyError: + path = d.entry_abspath(DB_Name) + try: db = DataBase[d] = DB_Module.open(path, mode) + except (IOError, OSError): pass + else: + if mode != "r": + DB_sync_list.append(db) + return db, mode + mode = "r" + try: + return DataBase[top], "c" + except KeyError: + db = DataBase[top] = DB_Module.open(DB_Name, "c") + DB_sync_list.append(db) + return db, "c" + except TypeError: + print("DataBase =", DataBase) + raise + + +def Reset(): + """Reset global state. Used by unit tests that end up using + SConsign multiple times to get a clean slate for each test.""" + global sig_files, DB_sync_list + sig_files = [] + DB_sync_list = [] + +normcase = os.path.normcase + + +def write(): + global sig_files + for sig_file in sig_files: + sig_file.write(sync=0) + for db in DB_sync_list: + try: + syncmethod = db.sync + except AttributeError: + pass # Not all dbm modules have sync() methods. + else: + syncmethod() + try: + closemethod = db.close + except AttributeError: + pass # Not all dbm modules have close() methods. + else: + closemethod() + + +class SConsignEntry(object): + """ + Wrapper class for the generic entry in a .sconsign file. + The Node subclass populates it with attributes as it pleases. + + XXX As coded below, we do expect a '.binfo' attribute to be added, + but we'll probably generalize this in the next refactorings. + """ + __slots__ = ("binfo", "ninfo", "__weakref__") + current_version_id = 2 + + def __init__(self): + # Create an object attribute from the class attribute so it ends up + # in the pickled data in the .sconsign file. + #_version_id = self.current_version_id + pass + + def convert_to_sconsign(self): + self.binfo.convert_to_sconsign() + + def convert_from_sconsign(self, dir, name): + self.binfo.convert_from_sconsign(dir, name) + + def __getstate__(self): + state = getattr(self, '__dict__', {}).copy() + for obj in type(self).mro(): + for name in getattr(obj,'__slots__',()): + if hasattr(self, name): + state[name] = getattr(self, name) + + state['_version_id'] = self.current_version_id + try: + del state['__weakref__'] + except KeyError: + pass + return state + + def __setstate__(self, state): + for key, value in state.items(): + if key not in ('_version_id','__weakref__'): + setattr(self, key, value) + + +class Base(object): + """ + This is the controlling class for the signatures for the collection of + entries associated with a specific directory. The actual directory + association will be maintained by a subclass that is specific to + the underlying storage method. This class provides a common set of + methods for fetching and storing the individual bits of information + that make up signature entry. + """ + def __init__(self): + self.entries = {} + self.dirty = False + self.to_be_merged = {} + + def get_entry(self, filename): + """ + Fetch the specified entry attribute. + """ + return self.entries[filename] + + def set_entry(self, filename, obj): + """ + Set the entry. + """ + self.entries[filename] = obj + self.dirty = True + + def do_not_set_entry(self, filename, obj): + pass + + def store_info(self, filename, node): + entry = node.get_stored_info() + entry.binfo.merge(node.get_binfo()) + self.to_be_merged[filename] = node + self.dirty = True + + def do_not_store_info(self, filename, node): + pass + + def merge(self): + for key, node in self.to_be_merged.items(): + entry = node.get_stored_info() + try: + ninfo = entry.ninfo + except AttributeError: + # This happens with SConf Nodes, because the configuration + # subsystem takes direct control over how the build decision + # is made and its information stored. + pass + else: + ninfo.merge(node.get_ninfo()) + self.entries[key] = entry + self.to_be_merged = {} + + +class DB(Base): + """ + A Base subclass that reads and writes signature information + from a global .sconsign.db* file--the actual file suffix is + determined by the database module. + """ + def __init__(self, dir): + Base.__init__(self) + + self.dir = dir + + db, mode = Get_DataBase(dir) + + # Read using the path relative to the top of the Repository + # (self.dir.tpath) from which we're fetching the signature + # information. + path = normcase(dir.get_tpath()) + try: + rawentries = db[path] + except KeyError: + pass + else: + try: + self.entries = pickle.loads(rawentries) + if not isinstance(self.entries, dict): + self.entries = {} + raise TypeError + except KeyboardInterrupt: + raise + except Exception as e: + SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning, + "Ignoring corrupt sconsign entry : %s (%s)\n"%(self.dir.get_tpath(), e)) + for key, entry in self.entries.items(): + entry.convert_from_sconsign(dir, key) + + if mode == "r": + # This directory is actually under a repository, which means + # likely they're reaching in directly for a dependency on + # a file there. Don't actually set any entry info, so we + # won't try to write to that .sconsign.dblite file. + self.set_entry = self.do_not_set_entry + self.store_info = self.do_not_store_info + + global sig_files + sig_files.append(self) + + def write(self, sync=1): + if not self.dirty: + return + + self.merge() + + db, mode = Get_DataBase(self.dir) + + # Write using the path relative to the top of the SConstruct + # directory (self.dir.path), not relative to the top of + # the Repository; we only write to our own .sconsign file, + # not to .sconsign files in Repositories. + path = normcase(self.dir.get_internal_path()) + for key, entry in self.entries.items(): + entry.convert_to_sconsign() + db[path] = pickle.dumps(self.entries, PICKLE_PROTOCOL) + + if sync: + try: + syncmethod = db.sync + except AttributeError: + # Not all anydbm modules have sync() methods. + pass + else: + syncmethod() + + +class Dir(Base): + def __init__(self, fp=None, dir=None): + """ + fp - file pointer to read entries from + """ + Base.__init__(self) + + if not fp: + return + + self.entries = pickle.load(fp) + if not isinstance(self.entries, dict): + self.entries = {} + raise TypeError + + if dir: + for key, entry in self.entries.items(): + entry.convert_from_sconsign(dir, key) + + +class DirFile(Dir): + """ + Encapsulates reading and writing a per-directory .sconsign file. + """ + def __init__(self, dir): + """ + dir - the directory for the file + """ + + self.dir = dir + self.sconsign = os.path.join(dir.get_internal_path(), '.sconsign') + + try: + fp = open(self.sconsign, 'rb') + except IOError: + fp = None + + try: + Dir.__init__(self, fp, dir) + except KeyboardInterrupt: + raise + except: + SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning, + "Ignoring corrupt .sconsign file: %s"%self.sconsign) + + global sig_files + sig_files.append(self) + + def write(self, sync=1): + """ + Write the .sconsign file to disk. + + Try to write to a temporary file first, and rename it if we + succeed. If we can't write to the temporary file, it's + probably because the directory isn't writable (and if so, + how did we build anything in this directory, anyway?), so + try to write directly to the .sconsign file as a backup. + If we can't rename, try to copy the temporary contents back + to the .sconsign file. Either way, always try to remove + the temporary file at the end. + """ + if not self.dirty: + return + + self.merge() + + temp = os.path.join(self.dir.get_internal_path(), '.scons%d' % os.getpid()) + try: + file = open(temp, 'wb') + fname = temp + except IOError: + try: + file = open(self.sconsign, 'wb') + fname = self.sconsign + except IOError: + return + for key, entry in self.entries.items(): + entry.convert_to_sconsign() + pickle.dump(self.entries, file, PICKLE_PROTOCOL) + file.close() + if fname != self.sconsign: + try: + mode = os.stat(self.sconsign)[0] + os.chmod(self.sconsign, 0o666) + os.unlink(self.sconsign) + except (IOError, OSError): + # Try to carry on in the face of either OSError + # (things like permission issues) or IOError (disk + # or network issues). If there's a really dangerous + # issue, it should get re-raised by the calls below. + pass + try: + os.rename(fname, self.sconsign) + except OSError: + # An OSError failure to rename may indicate something + # like the directory has no write permission, but + # the .sconsign file itself might still be writable, + # so try writing on top of it directly. An IOError + # here, or in any of the following calls, would get + # raised, indicating something like a potentially + # serious disk or network issue. + with open(self.sconsign, 'wb') as f, open(fname, 'rb') as f2: + f.write(f2.read()) + os.chmod(self.sconsign, mode) + try: + os.unlink(temp) + except (IOError, OSError): + pass + +ForDirectory = DB + + +def File(name, dbm_module=None): + """ + Arrange for all signatures to be stored in a global .sconsign.db* + file. + """ + global ForDirectory, DB_Name, DB_Module + if name is None: + ForDirectory = DirFile + DB_Module = None + else: + ForDirectory = DB + DB_Name = name + if not dbm_module is None: + DB_Module = dbm_module + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Scanner/C.py b/tools/scons/scons-local-3.0.5/SCons/Scanner/C.py new file mode 100755 index 0000000000..6f59edbbb7 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Scanner/C.py @@ -0,0 +1,131 @@ +"""SCons.Scanner.C + +This module implements the dependency scanner for C/C++ code. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Scanner/C.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Node.FS +import SCons.Scanner +import SCons.Util + +import SCons.cpp + +class SConsCPPScanner(SCons.cpp.PreProcessor): + """ + SCons-specific subclass of the cpp.py module's processing. + + We subclass this so that: 1) we can deal with files represented + by Nodes, not strings; 2) we can keep track of the files that are + missing. + """ + def __init__(self, *args, **kw): + SCons.cpp.PreProcessor.__init__(self, *args, **kw) + self.missing = [] + def initialize_result(self, fname): + self.result = SCons.Util.UniqueList([fname]) + def finalize_result(self, fname): + return self.result[1:] + def find_include_file(self, t): + keyword, quote, fname = t + result = SCons.Node.FS.find_file(fname, self.searchpath[quote]) + if not result: + self.missing.append((fname, self.current_file)) + return result + def read_file(self, file): + try: + with open(str(file.rfile())) as fp: + return fp.read() + except EnvironmentError as e: + self.missing.append((file, self.current_file)) + return '' + +def dictify_CPPDEFINES(env): + cppdefines = env.get('CPPDEFINES', {}) + if cppdefines is None: + return {} + if SCons.Util.is_Sequence(cppdefines): + result = {} + for c in cppdefines: + if SCons.Util.is_Sequence(c): + result[c[0]] = c[1] + else: + result[c] = None + return result + if not SCons.Util.is_Dict(cppdefines): + return {cppdefines : None} + return cppdefines + +class SConsCPPScannerWrapper(object): + """ + The SCons wrapper around a cpp.py scanner. + + This is the actual glue between the calling conventions of generic + SCons scanners, and the (subclass of) cpp.py class that knows how + to look for #include lines with reasonably real C-preprocessor-like + evaluation of #if/#ifdef/#else/#elif lines. + """ + def __init__(self, name, variable): + self.name = name + self.path = SCons.Scanner.FindPathDirs(variable) + def __call__(self, node, env, path = ()): + cpp = SConsCPPScanner(current = node.get_dir(), + cpppath = path, + dict = dictify_CPPDEFINES(env)) + result = cpp(node) + for included, includer in cpp.missing: + fmt = "No dependency generated for file: %s (included from: %s) -- file not found" + SCons.Warnings.warn(SCons.Warnings.DependencyWarning, + fmt % (included, includer)) + return result + + def recurse_nodes(self, nodes): + return nodes + def select(self, node): + return self + +def CScanner(): + """Return a prototype Scanner instance for scanning source files + that use the C pre-processor""" + + # Here's how we would (or might) use the CPP scanner code above that + # knows how to evaluate #if/#ifdef/#else/#elif lines when searching + # for #includes. This is commented out for now until we add the + # right configurability to let users pick between the scanners. + #return SConsCPPScannerWrapper("CScanner", "CPPPATH") + + cs = SCons.Scanner.ClassicCPP("CScanner", + "$CPPSUFFIXES", + "CPPPATH", + '^[ \t]*#[ \t]*(?:include|import)[ \t]*(<|")([^>"]+)(>|")') + return cs + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Scanner/D.py b/tools/scons/scons-local-3.0.5/SCons/Scanner/D.py new file mode 100755 index 0000000000..543cc3c12a --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Scanner/D.py @@ -0,0 +1,73 @@ +"""SCons.Scanner.D + +Scanner for the Digital Mars "D" programming language. + +Coded by Andy Friesen +17 Nov 2003 + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Scanner/D.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Scanner + +def DScanner(): + """Return a prototype Scanner instance for scanning D source files""" + ds = D() + return ds + +class D(SCons.Scanner.Classic): + def __init__ (self): + SCons.Scanner.Classic.__init__ ( + self, + name = "DScanner", + suffixes = '$DSUFFIXES', + path_variable = 'DPATH', + regex = '(?:import\s+)([\w\s=,.]+)(?:\s*:[\s\w,=]+)?(?:;)' + ) + + def find_include(self, include, source_dir, path): + # translate dots (package separators) to slashes + inc = include.replace('.', '/') + + i = SCons.Node.FS.find_file(inc + '.d', (source_dir,) + path) + if i is None: + i = SCons.Node.FS.find_file (inc + '.di', (source_dir,) + path) + return i, include + + def find_include_names(self, node): + includes = [] + for iii in self.cre.findall(node.get_text_contents()): + for jjj in iii.split(','): + kkk = jjj.split('=')[-1] + includes.append(kkk.strip()) + return includes + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Scanner/Dir.py b/tools/scons/scons-local-3.0.5/SCons/Scanner/Dir.py new file mode 100755 index 0000000000..1b8204665a --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Scanner/Dir.py @@ -0,0 +1,109 @@ +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +__revision__ = "src/engine/SCons/Scanner/Dir.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Node.FS +import SCons.Scanner + +def only_dirs(nodes): + is_Dir = lambda n: isinstance(n.disambiguate(), SCons.Node.FS.Dir) + return [node for node in nodes if is_Dir(node)] + +def DirScanner(**kw): + """Return a prototype Scanner instance for scanning + directories for on-disk files""" + kw['node_factory'] = SCons.Node.FS.Entry + kw['recursive'] = only_dirs + return SCons.Scanner.Base(scan_on_disk, "DirScanner", **kw) + +def DirEntryScanner(**kw): + """Return a prototype Scanner instance for "scanning" + directory Nodes for their in-memory entries""" + kw['node_factory'] = SCons.Node.FS.Entry + kw['recursive'] = None + return SCons.Scanner.Base(scan_in_memory, "DirEntryScanner", **kw) + +skip_entry = {} + +skip_entry_list = [ + '.', + '..', + '.sconsign', + # Used by the native dblite.py module. + '.sconsign.dblite', + # Used by dbm and dumbdbm. + '.sconsign.dir', + # Used by dbm. + '.sconsign.pag', + # Used by dumbdbm. + '.sconsign.dat', + '.sconsign.bak', + # Used by some dbm emulations using Berkeley DB. + '.sconsign.db', +] + +for skip in skip_entry_list: + skip_entry[skip] = 1 + skip_entry[SCons.Node.FS._my_normcase(skip)] = 1 + +do_not_scan = lambda k: k not in skip_entry + +def scan_on_disk(node, env, path=()): + """ + Scans a directory for on-disk files and directories therein. + + Looking up the entries will add these to the in-memory Node tree + representation of the file system, so all we have to do is just + that and then call the in-memory scanning function. + """ + try: + flist = node.fs.listdir(node.get_abspath()) + except (IOError, OSError): + return [] + e = node.Entry + for f in filter(do_not_scan, flist): + # Add ./ to the beginning of the file name so if it begins with a + # '#' we don't look it up relative to the top-level directory. + e('./' + f) + return scan_in_memory(node, env, path) + +def scan_in_memory(node, env, path=()): + """ + "Scans" a Node.FS.Dir for its in-memory entries. + """ + try: + entries = node.entries + except AttributeError: + # It's not a Node.FS.Dir (or doesn't look enough like one for + # our purposes), which can happen if a target list containing + # mixed Node types (Dirs and Files, for example) has a Dir as + # the first entry. + return [] + entry_list = sorted(filter(do_not_scan, list(entries.keys()))) + return [entries[n] for n in entry_list] + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Scanner/Fortran.py b/tools/scons/scons-local-3.0.5/SCons/Scanner/Fortran.py new file mode 100755 index 0000000000..b52269fd57 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Scanner/Fortran.py @@ -0,0 +1,316 @@ +"""SCons.Scanner.Fortran + +This module implements the dependency scanner for Fortran code. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +__revision__ = "src/engine/SCons/Scanner/Fortran.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import re + +import SCons.Node +import SCons.Node.FS +import SCons.Scanner +import SCons.Util +import SCons.Warnings + +class F90Scanner(SCons.Scanner.Classic): + """ + A Classic Scanner subclass for Fortran source files which takes + into account both USE and INCLUDE statements. This scanner will + work for both F77 and F90 (and beyond) compilers. + + Currently, this scanner assumes that the include files do not contain + USE statements. To enable the ability to deal with USE statements + in include files, add logic right after the module names are found + to loop over each include file, search for and locate each USE + statement, and append each module name to the list of dependencies. + Caching the search results in a common dictionary somewhere so that + the same include file is not searched multiple times would be a + smart thing to do. + """ + + def __init__(self, name, suffixes, path_variable, + use_regex, incl_regex, def_regex, *args, **kw): + + self.cre_use = re.compile(use_regex, re.M) + self.cre_incl = re.compile(incl_regex, re.M) + self.cre_def = re.compile(def_regex, re.M) + + def _scan(node, env, path, self=self): + node = node.rfile() + + if not node.exists(): + return [] + + return self.scan(node, env, path) + + kw['function'] = _scan + kw['path_function'] = SCons.Scanner.FindPathDirs(path_variable) + kw['recursive'] = 1 + kw['skeys'] = suffixes + kw['name'] = name + + SCons.Scanner.Current.__init__(self, *args, **kw) + + def scan(self, node, env, path=()): + + # cache the includes list in node so we only scan it once: + if node.includes is not None: + mods_and_includes = node.includes + else: + # retrieve all included filenames + includes = self.cre_incl.findall(node.get_text_contents()) + # retrieve all USE'd module names + modules = self.cre_use.findall(node.get_text_contents()) + # retrieve all defined module names + defmodules = self.cre_def.findall(node.get_text_contents()) + + # Remove all USE'd module names that are defined in the same file + # (case-insensitively) + d = {} + for m in defmodules: + d[m.lower()] = 1 + modules = [m for m in modules if m.lower() not in d] + + # Convert module name to a .mod filename + suffix = env.subst('$FORTRANMODSUFFIX') + modules = [x.lower() + suffix for x in modules] + # Remove unique items from the list + mods_and_includes = SCons.Util.unique(includes+modules) + node.includes = mods_and_includes + + # This is a hand-coded DSU (decorate-sort-undecorate, or + # Schwartzian transform) pattern. The sort key is the raw name + # of the file as specifed on the USE or INCLUDE line, which lets + # us keep the sort order constant regardless of whether the file + # is actually found in a Repository or locally. + nodes = [] + source_dir = node.get_dir() + if callable(path): + path = path() + for dep in mods_and_includes: + n, i = self.find_include(dep, source_dir, path) + + if n is None: + SCons.Warnings.warn(SCons.Warnings.DependencyWarning, + "No dependency generated for file: %s (referenced by: %s) -- file not found" % (i, node)) + else: + sortkey = self.sort_key(dep) + nodes.append((sortkey, n)) + + return [pair[1] for pair in sorted(nodes)] + +def FortranScan(path_variable="FORTRANPATH"): + """Return a prototype Scanner instance for scanning source files + for Fortran USE & INCLUDE statements""" + +# The USE statement regex matches the following: +# +# USE module_name +# USE :: module_name +# USE, INTRINSIC :: module_name +# USE, NON_INTRINSIC :: module_name +# +# Limitations +# +# -- While the regex can handle multiple USE statements on one line, +# it cannot properly handle them if they are commented out. +# In either of the following cases: +# +# ! USE mod_a ; USE mod_b [entire line is commented out] +# USE mod_a ! ; USE mod_b [in-line comment of second USE statement] +# +# the second module name (mod_b) will be picked up as a dependency +# even though it should be ignored. The only way I can see +# to rectify this would be to modify the scanner to eliminate +# the call to re.findall, read in the contents of the file, +# treating the comment character as an end-of-line character +# in addition to the normal linefeed, loop over each line, +# weeding out the comments, and looking for the USE statements. +# One advantage to this is that the regex passed to the scanner +# would no longer need to match a semicolon. +# +# -- I question whether or not we need to detect dependencies to +# INTRINSIC modules because these are built-in to the compiler. +# If we consider them a dependency, will SCons look for them, not +# find them, and kill the build? Or will we there be standard +# compiler-specific directories we will need to point to so the +# compiler and SCons can locate the proper object and mod files? + +# Here is a breakdown of the regex: +# +# (?i) : regex is case insensitive +# ^ : start of line +# (?: : group a collection of regex symbols without saving the match as a "group" +# ^|; : matches either the start of the line or a semicolon - semicolon +# ) : end the unsaved grouping +# \s* : any amount of white space +# USE : match the string USE, case insensitive +# (?: : group a collection of regex symbols without saving the match as a "group" +# \s+| : match one or more whitespace OR .... (the next entire grouped set of regex symbols) +# (?: : group a collection of regex symbols without saving the match as a "group" +# (?: : establish another unsaved grouping of regex symbols +# \s* : any amount of white space +# , : match a comma +# \s* : any amount of white space +# (?:NON_)? : optionally match the prefix NON_, case insensitive +# INTRINSIC : match the string INTRINSIC, case insensitive +# )? : optionally match the ", INTRINSIC/NON_INTRINSIC" grouped expression +# \s* : any amount of white space +# :: : match a double colon that must appear after the INTRINSIC/NON_INTRINSIC attribute +# ) : end the unsaved grouping +# ) : end the unsaved grouping +# \s* : match any amount of white space +# (\w+) : match the module name that is being USE'd +# +# + use_regex = "(?i)(?:^|;)\s*USE(?:\s+|(?:(?:\s*,\s*(?:NON_)?INTRINSIC)?\s*::))\s*(\w+)" + + +# The INCLUDE statement regex matches the following: +# +# INCLUDE 'some_Text' +# INCLUDE "some_Text" +# INCLUDE "some_Text" ; INCLUDE "some_Text" +# INCLUDE kind_"some_Text" +# INCLUDE kind_'some_Text" +# +# where some_Text can include any alphanumeric and/or special character +# as defined by the Fortran 2003 standard. +# +# Limitations: +# +# -- The Fortran standard dictates that a " or ' in the INCLUDE'd +# string must be represented as a "" or '', if the quotes that wrap +# the entire string are either a ' or ", respectively. While the +# regular expression below can detect the ' or " characters just fine, +# the scanning logic, presently is unable to detect them and reduce +# them to a single instance. This probably isn't an issue since, +# in practice, ' or " are not generally used in filenames. +# +# -- This regex will not properly deal with multiple INCLUDE statements +# when the entire line has been commented out, ala +# +# ! INCLUDE 'some_file' ; INCLUDE 'some_file' +# +# In such cases, it will properly ignore the first INCLUDE file, +# but will actually still pick up the second. Interestingly enough, +# the regex will properly deal with these cases: +# +# INCLUDE 'some_file' +# INCLUDE 'some_file' !; INCLUDE 'some_file' +# +# To get around the above limitation, the FORTRAN programmer could +# simply comment each INCLUDE statement separately, like this +# +# ! INCLUDE 'some_file' !; INCLUDE 'some_file' +# +# The way I see it, the only way to get around this limitation would +# be to modify the scanning logic to replace the calls to re.findall +# with a custom loop that processes each line separately, throwing +# away fully commented out lines before attempting to match against +# the INCLUDE syntax. +# +# Here is a breakdown of the regex: +# +# (?i) : regex is case insensitive +# (?: : begin a non-saving group that matches the following: +# ^ : either the start of the line +# | : or +# ['">]\s*; : a semicolon that follows a single quote, +# double quote or greater than symbol (with any +# amount of whitespace in between). This will +# allow the regex to match multiple INCLUDE +# statements per line (although it also requires +# the positive lookahead assertion that is +# used below). It will even properly deal with +# (i.e. ignore) cases in which the additional +# INCLUDES are part of an in-line comment, ala +# " INCLUDE 'someFile' ! ; INCLUDE 'someFile2' " +# ) : end of non-saving group +# \s* : any amount of white space +# INCLUDE : match the string INCLUDE, case insensitive +# \s+ : match one or more white space characters +# (?\w+_)? : match the optional "kind-param _" prefix allowed by the standard +# [<"'] : match the include delimiter - an apostrophe, double quote, or less than symbol +# (.+?) : match one or more characters that make up +# the included path and file name and save it +# in a group. The Fortran standard allows for +# any non-control character to be used. The dot +# operator will pick up any character, including +# control codes, but I can't conceive of anyone +# putting control codes in their file names. +# The question mark indicates it is non-greedy so +# that regex will match only up to the next quote, +# double quote, or greater than symbol +# (?=["'>]) : positive lookahead assertion to match the include +# delimiter - an apostrophe, double quote, or +# greater than symbol. This level of complexity +# is required so that the include delimiter is +# not consumed by the match, thus allowing the +# sub-regex discussed above to uniquely match a +# set of semicolon-separated INCLUDE statements +# (as allowed by the F2003 standard) + + include_regex = """(?i)(?:^|['">]\s*;)\s*INCLUDE\s+(?:\w+_)?[<"'](.+?)(?=["'>])""" + +# The MODULE statement regex finds module definitions by matching +# the following: +# +# MODULE module_name +# +# but *not* the following: +# +# MODULE PROCEDURE procedure_name +# +# Here is a breakdown of the regex: +# +# (?i) : regex is case insensitive +# ^\s* : any amount of white space +# MODULE : match the string MODULE, case insensitive +# \s+ : match one or more white space characters +# (?!PROCEDURE) : but *don't* match if the next word matches +# PROCEDURE (negative lookahead assertion), +# case insensitive +# (\w+) : match one or more alphanumeric characters +# that make up the defined module name and +# save it in a group + + def_regex = """(?i)^\s*MODULE\s+(?!PROCEDURE)(\w+)""" + + scanner = F90Scanner("FortranScan", + "$FORTRANSUFFIXES", + path_variable, + use_regex, + include_regex, + def_regex) + return scanner + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Scanner/IDL.py b/tools/scons/scons-local-3.0.5/SCons/Scanner/IDL.py new file mode 100755 index 0000000000..843a1478c3 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Scanner/IDL.py @@ -0,0 +1,48 @@ +"""SCons.Scanner.IDL + +This module implements the dependency scanner for IDL (Interface +Definition Language) files. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Scanner/IDL.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Node.FS +import SCons.Scanner + +def IDLScan(): + """Return a prototype Scanner instance for scanning IDL source files""" + cs = SCons.Scanner.ClassicCPP("IDLScan", + "$IDLSUFFIXES", + "CPPPATH", + '^[ \t]*(?:#[ \t]*include|[ \t]*import)[ \t]+(<|")([^>"]+)(>|")') + return cs + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Scanner/LaTeX.py b/tools/scons/scons-local-3.0.5/SCons/Scanner/LaTeX.py new file mode 100755 index 0000000000..d9e369251b --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Scanner/LaTeX.py @@ -0,0 +1,437 @@ +"""SCons.Scanner.LaTeX + +This module implements the dependency scanner for LaTeX code. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Scanner/LaTeX.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os.path +import re + +import SCons.Scanner +import SCons.Util + +# list of graphics file extensions for TeX and LaTeX +TexGraphics = ['.eps', '.ps'] +#LatexGraphics = ['.pdf', '.png', '.jpg', '.gif', '.tif'] +LatexGraphics = [ '.png', '.jpg', '.gif', '.tif'] + + +# Used as a return value of modify_env_var if the variable is not set. +class _Null(object): + pass +_null = _Null + +# The user specifies the paths in env[variable], similar to other builders. +# They may be relative and must be converted to absolute, as expected +# by LaTeX and Co. The environment may already have some paths in +# env['ENV'][var]. These paths are honored, but the env[var] paths have +# higher precedence. All changes are un-done on exit. +def modify_env_var(env, var, abspath): + try: + save = env['ENV'][var] + except KeyError: + save = _null + env.PrependENVPath(var, abspath) + try: + if SCons.Util.is_List(env[var]): + env.PrependENVPath(var, [os.path.abspath(str(p)) for p in env[var]]) + else: + # Split at os.pathsep to convert into absolute path + env.PrependENVPath(var, [os.path.abspath(p) for p in str(env[var]).split(os.pathsep)]) + except KeyError: + pass + + # Convert into a string explicitly to append ":" (without which it won't search system + # paths as well). The problem is that env.AppendENVPath(var, ":") + # does not work, refuses to append ":" (os.pathsep). + + if SCons.Util.is_List(env['ENV'][var]): + env['ENV'][var] = os.pathsep.join(env['ENV'][var]) + # Append the trailing os.pathsep character here to catch the case with no env[var] + env['ENV'][var] = env['ENV'][var] + os.pathsep + + return save + +class FindENVPathDirs(object): + """ + A class to bind a specific E{*}PATH variable name to a function that + will return all of the E{*}path directories. + """ + def __init__(self, variable): + self.variable = variable + def __call__(self, env, dir=None, target=None, source=None, argument=None): + import SCons.PathList + try: + path = env['ENV'][self.variable] + except KeyError: + return () + + dir = dir or env.fs._cwd + path = SCons.PathList.PathList(path).subst_path(env, target, source) + return tuple(dir.Rfindalldirs(path)) + + + +def LaTeXScanner(): + """ + Return a prototype Scanner instance for scanning LaTeX source files + when built with latex. + """ + ds = LaTeX(name = "LaTeXScanner", + suffixes = '$LATEXSUFFIXES', + # in the search order, see below in LaTeX class docstring + graphics_extensions = TexGraphics, + recursive = 0) + return ds + +def PDFLaTeXScanner(): + """ + Return a prototype Scanner instance for scanning LaTeX source files + when built with pdflatex. + """ + ds = LaTeX(name = "PDFLaTeXScanner", + suffixes = '$LATEXSUFFIXES', + # in the search order, see below in LaTeX class docstring + graphics_extensions = LatexGraphics, + recursive = 0) + return ds + +class LaTeX(SCons.Scanner.Base): + """ + Class for scanning LaTeX files for included files. + + Unlike most scanners, which use regular expressions that just + return the included file name, this returns a tuple consisting + of the keyword for the inclusion ("include", "includegraphics", + "input", or "bibliography"), and then the file name itself. + Based on a quick look at LaTeX documentation, it seems that we + should append .tex suffix for the "include" keywords, append .tex if + there is no extension for the "input" keyword, and need to add .bib + for the "bibliography" keyword that does not accept extensions by itself. + + Finally, if there is no extension for an "includegraphics" keyword + latex will append .ps or .eps to find the file, while pdftex may use .pdf, + .jpg, .tif, .mps, or .png. + + The actual subset and search order may be altered by + DeclareGraphicsExtensions command. This complication is ignored. + The default order corresponds to experimentation with teTeX:: + + $ latex --version + pdfeTeX 3.141592-1.21a-2.2 (Web2C 7.5.4) + kpathsea version 3.5.4 + + The order is: + ['.eps', '.ps'] for latex + ['.png', '.pdf', '.jpg', '.tif']. + + Another difference is that the search path is determined by the type + of the file being searched: + env['TEXINPUTS'] for "input" and "include" keywords + env['TEXINPUTS'] for "includegraphics" keyword + env['TEXINPUTS'] for "lstinputlisting" keyword + env['BIBINPUTS'] for "bibliography" keyword + env['BSTINPUTS'] for "bibliographystyle" keyword + env['INDEXSTYLE'] for "makeindex" keyword, no scanning support needed just allows user to set it if needed. + + FIXME: also look for the class or style in document[class|style]{} + FIXME: also look for the argument of bibliographystyle{} + """ + keyword_paths = {'include': 'TEXINPUTS', + 'input': 'TEXINPUTS', + 'includegraphics': 'TEXINPUTS', + 'bibliography': 'BIBINPUTS', + 'bibliographystyle': 'BSTINPUTS', + 'addbibresource': 'BIBINPUTS', + 'addglobalbib': 'BIBINPUTS', + 'addsectionbib': 'BIBINPUTS', + 'makeindex': 'INDEXSTYLE', + 'usepackage': 'TEXINPUTS', + 'lstinputlisting': 'TEXINPUTS'} + env_variables = SCons.Util.unique(list(keyword_paths.values())) + two_arg_commands = ['import', 'subimport', + 'includefrom', 'subincludefrom', + 'inputfrom', 'subinputfrom'] + + def __init__(self, name, suffixes, graphics_extensions, *args, **kw): + + # We have to include \n with the % we exclude from the first part + # part of the regex because the expression is compiled with re.M. + # Without the \n, the ^ could match the beginning of a *previous* + # line followed by one or more newline characters (i.e. blank + # lines), interfering with a match on the next line. + # add option for whitespace before the '[options]' or the '{filename}' + regex = r''' + ^[^%\n]* + \\( + include + | includegraphics(?:\s*\[[^\]]+\])? + | lstinputlisting(?:\[[^\]]+\])? + | input + | import + | subimport + | includefrom + | subincludefrom + | inputfrom + | subinputfrom + | bibliography + | addbibresource + | addglobalbib + | addsectionbib + | usepackage + ) + \s*{([^}]*)} # first arg + (?: \s*{([^}]*)} )? # maybe another arg + ''' + self.cre = re.compile(regex, re.M | re.X) + self.comment_re = re.compile(r'^((?:(?:\\%)|[^%\n])*)(.*)$', re.M) + + self.graphics_extensions = graphics_extensions + + def _scan(node, env, path=(), self=self): + node = node.rfile() + if not node.exists(): + return [] + return self.scan_recurse(node, path) + + class FindMultiPathDirs(object): + """The stock FindPathDirs function has the wrong granularity: + it is called once per target, while we need the path that depends + on what kind of included files is being searched. This wrapper + hides multiple instances of FindPathDirs, one per the LaTeX path + variable in the environment. When invoked, the function calculates + and returns all the required paths as a dictionary (converted into + a tuple to become hashable). Then the scan function converts it + back and uses a dictionary of tuples rather than a single tuple + of paths. + """ + def __init__(self, dictionary): + self.dictionary = {} + for k,n in dictionary.items(): + self.dictionary[k] = ( SCons.Scanner.FindPathDirs(n), + FindENVPathDirs(n) ) + + def __call__(self, env, dir=None, target=None, source=None, + argument=None): + di = {} + for k,(c,cENV) in self.dictionary.items(): + di[k] = ( c(env, dir=None, target=None, source=None, + argument=None) , + cENV(env, dir=None, target=None, source=None, + argument=None) ) + # To prevent "dict is not hashable error" + return tuple(di.items()) + + class LaTeXScanCheck(object): + """Skip all but LaTeX source files, i.e., do not scan *.eps, + *.pdf, *.jpg, etc. + """ + def __init__(self, suffixes): + self.suffixes = suffixes + def __call__(self, node, env): + current = not node.has_builder() or node.is_up_to_date() + scannable = node.get_suffix() in env.subst_list(self.suffixes)[0] + # Returning false means that the file is not scanned. + return scannable and current + + kw['function'] = _scan + kw['path_function'] = FindMultiPathDirs(LaTeX.keyword_paths) + kw['recursive'] = 0 + kw['skeys'] = suffixes + kw['scan_check'] = LaTeXScanCheck(suffixes) + kw['name'] = name + + SCons.Scanner.Base.__init__(self, *args, **kw) + + def _latex_names(self, include_type, filename): + if include_type == 'input': + base, ext = os.path.splitext( filename ) + if ext == "": + return [filename + '.tex'] + if include_type in ('include', 'import', 'subimport', + 'includefrom', 'subincludefrom', + 'inputfrom', 'subinputfrom'): + base, ext = os.path.splitext( filename ) + if ext == "": + return [filename + '.tex'] + if include_type == 'bibliography': + base, ext = os.path.splitext( filename ) + if ext == "": + return [filename + '.bib'] + if include_type == 'usepackage': + base, ext = os.path.splitext( filename ) + if ext == "": + return [filename + '.sty'] + if include_type == 'includegraphics': + base, ext = os.path.splitext( filename ) + if ext == "": + #return [filename+e for e in self.graphics_extensions + TexGraphics] + # use the line above to find dependencies for the PDF builder + # when only an .eps figure is present. Since it will be found + # if the user tells scons how to make the pdf figure, leave + # it out for now. + return [filename+e for e in self.graphics_extensions] + return [filename] + + def sort_key(self, include): + return SCons.Node.FS._my_normcase(str(include)) + + def find_include(self, include, source_dir, path): + inc_type, inc_subdir, inc_filename = include + try: + sub_paths = path[inc_type] + except (IndexError, KeyError): + sub_paths = ((), ()) + try_names = self._latex_names(inc_type, inc_filename) + + # There are three search paths to try: + # 1. current directory "source_dir" + # 2. env[var] + # 3. env['ENV'][var] + search_paths = [(source_dir,)] + list(sub_paths) + + for n in try_names: + for search_path in search_paths: + paths = tuple([d.Dir(inc_subdir) for d in search_path]) + i = SCons.Node.FS.find_file(n, paths) + if i: + return i, include + return None, include + + def canonical_text(self, text): + """Standardize an input TeX-file contents. + + Currently: + * removes comments, unwrapping comment-wrapped lines. + """ + out = [] + line_continues_a_comment = False + for line in text.splitlines(): + line,comment = self.comment_re.findall(line)[0] + if line_continues_a_comment: + out[-1] = out[-1] + line.lstrip() + else: + out.append(line) + line_continues_a_comment = len(comment) > 0 + return '\n'.join(out).rstrip()+'\n' + + def scan(self, node, subdir='.'): + # Modify the default scan function to allow for the regular + # expression to return a comma separated list of file names + # as can be the case with the bibliography keyword. + + # Cache the includes list in node so we only scan it once: + # path_dict = dict(list(path)) + # add option for whitespace (\s) before the '[' + noopt_cre = re.compile('\s*\[.*$') + if node.includes is not None: + includes = node.includes + else: + text = self.canonical_text(node.get_text_contents()) + includes = self.cre.findall(text) + # 1. Split comma-separated lines, e.g. + # ('bibliography', 'phys,comp') + # should become two entries + # ('bibliography', 'phys') + # ('bibliography', 'comp') + # 2. Remove the options, e.g., such as + # ('includegraphics[clip,width=0.7\\linewidth]', 'picture.eps') + # should become + # ('includegraphics', 'picture.eps') + split_includes = [] + for include in includes: + inc_type = noopt_cre.sub('', include[0]) + inc_subdir = subdir + if inc_type in self.two_arg_commands: + inc_subdir = os.path.join(subdir, include[1]) + inc_list = include[2].split(',') + else: + inc_list = include[1].split(',') + for j in range(len(inc_list)): + split_includes.append( (inc_type, inc_subdir, inc_list[j]) ) + # + includes = split_includes + node.includes = includes + + return includes + + def scan_recurse(self, node, path=()): + """ do a recursive scan of the top level target file + This lets us search for included files based on the + directory of the main file just as latex does""" + + path_dict = dict(list(path)) + + queue = [] + queue.extend( self.scan(node) ) + seen = {} + + # This is a hand-coded DSU (decorate-sort-undecorate, or + # Schwartzian transform) pattern. The sort key is the raw name + # of the file as specifed on the \include, \input, etc. line. + # TODO: what about the comment in the original Classic scanner: + # """which lets + # us keep the sort order constant regardless of whether the file + # is actually found in a Repository or locally.""" + nodes = [] + source_dir = node.get_dir() + #for include in includes: + while queue: + + include = queue.pop() + inc_type, inc_subdir, inc_filename = include + + try: + if seen[inc_filename] == 1: + continue + except KeyError: + seen[inc_filename] = 1 + + # + # Handle multiple filenames in include[1] + # + n, i = self.find_include(include, source_dir, path_dict) + if n is None: + # Do not bother with 'usepackage' warnings, as they most + # likely refer to system-level files + if inc_type != 'usepackage': + SCons.Warnings.warn(SCons.Warnings.DependencyWarning, + "No dependency generated for file: %s (included from: %s) -- file not found" % (i, node)) + else: + sortkey = self.sort_key(n) + nodes.append((sortkey, n)) + # recurse down + queue.extend( self.scan(n, inc_subdir) ) + + return [pair[1] for pair in sorted(nodes)] + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Scanner/Prog.py b/tools/scons/scons-local-3.0.5/SCons/Scanner/Prog.py new file mode 100755 index 0000000000..78deb18674 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Scanner/Prog.py @@ -0,0 +1,116 @@ +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Scanner/Prog.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Node +import SCons.Node.FS +import SCons.Scanner +import SCons.Util + +# global, set by --debug=findlibs +print_find_libs = None + +def ProgramScanner(**kw): + """Return a prototype Scanner instance for scanning executable + files for static-lib dependencies""" + kw['path_function'] = SCons.Scanner.FindPathDirs('LIBPATH') + ps = SCons.Scanner.Base(scan, "ProgramScanner", **kw) + return ps + +def _subst_libs(env, libs): + """ + Substitute environment variables and split into list. + """ + if SCons.Util.is_String(libs): + libs = env.subst(libs) + if SCons.Util.is_String(libs): + libs = libs.split() + elif SCons.Util.is_Sequence(libs): + _libs = [] + for l in libs: + _libs += _subst_libs(env, l) + libs = _libs + else: + # libs is an object (Node, for example) + libs = [libs] + return libs + +def scan(node, env, libpath = ()): + """ + This scanner scans program files for static-library + dependencies. It will search the LIBPATH environment variable + for libraries specified in the LIBS variable, returning any + files it finds as dependencies. + """ + try: + libs = env['LIBS'] + except KeyError: + # There are no LIBS in this environment, so just return a null list: + return [] + + libs = _subst_libs(env, libs) + + try: + prefix = env['LIBPREFIXES'] + if not SCons.Util.is_List(prefix): + prefix = [ prefix ] + except KeyError: + prefix = [ '' ] + + try: + suffix = env['LIBSUFFIXES'] + if not SCons.Util.is_List(suffix): + suffix = [ suffix ] + except KeyError: + suffix = [ '' ] + + pairs = [] + for suf in map(env.subst, suffix): + for pref in map(env.subst, prefix): + pairs.append((pref, suf)) + + result = [] + + if callable(libpath): + libpath = libpath() + + find_file = SCons.Node.FS.find_file + adjustixes = SCons.Util.adjustixes + for lib in libs: + if SCons.Util.is_String(lib): + for pref, suf in pairs: + l = adjustixes(lib, pref, suf) + l = find_file(l, libpath, verbose=print_find_libs) + if l: + result.append(l) + else: + result.append(lib) + + return result + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Scanner/RC.py b/tools/scons/scons-local-3.0.5/SCons/Scanner/RC.py new file mode 100755 index 0000000000..cf970c5283 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Scanner/RC.py @@ -0,0 +1,66 @@ +"""SCons.Scanner.RC + +This module implements the dependency scanner for RC (Interface +Definition Language) files. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Scanner/RC.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import re + +import SCons.Node.FS +import SCons.Scanner + + +def no_tlb(nodes): + """ + Filter out .tlb files as they are binary and shouldn't be scanned + """ + # print("Nodes:%s"%[str(n) for n in nodes]) + return [n for n in nodes if str(n)[-4:] != '.tlb'] + + +def RCScan(): + """Return a prototype Scanner instance for scanning RC source files""" + + res_re= r'^(?:\s*#\s*(?:include)|' \ + '.*?\s+(?:ICON|BITMAP|CURSOR|HTML|FONT|MESSAGETABLE|TYPELIB|REGISTRY|D3DFX)' \ + '\s*.*?)' \ + '\s*(<|"| )([^>"\s]+)(?:[>"\s])*$' + resScanner = SCons.Scanner.ClassicCPP("ResourceScanner", + "$RCSUFFIXES", + "CPPPATH", + res_re, + recursive=no_tlb) + + return resScanner + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Scanner/SWIG.py b/tools/scons/scons-local-3.0.5/SCons/Scanner/SWIG.py new file mode 100755 index 0000000000..6bffbe3511 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Scanner/SWIG.py @@ -0,0 +1,45 @@ +"""SCons.Scanner.SWIG + +This module implements the dependency scanner for SWIG code. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Scanner/SWIG.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Scanner + +SWIGSuffixes = [ '.i' ] + +def SWIGScanner(): + expr = '^[ \t]*%[ \t]*(?:include|import|extern)[ \t]*(<|"?)([^>\s"]+)(?:>|"?)' + scanner = SCons.Scanner.ClassicCPP("SWIGScanner", ".i", "SWIGPATH", expr) + return scanner + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Scanner/__init__.py b/tools/scons/scons-local-3.0.5/SCons/Scanner/__init__.py new file mode 100755 index 0000000000..b5df1cc5ff --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Scanner/__init__.py @@ -0,0 +1,421 @@ +"""SCons.Scanner + +The Scanner package for the SCons software construction utility. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Scanner/__init__.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import re + +import SCons.Node.FS +import SCons.Util + + +class _Null(object): + pass + +# This is used instead of None as a default argument value so None can be +# used as an actual argument value. +_null = _Null + +def Scanner(function, *args, **kw): + """ + Public interface factory function for creating different types + of Scanners based on the different types of "functions" that may + be supplied. + + TODO: Deprecate this some day. We've moved the functionality + inside the Base class and really don't need this factory function + any more. It was, however, used by some of our Tool modules, so + the call probably ended up in various people's custom modules + patterned on SCons code. + """ + if SCons.Util.is_Dict(function): + return Selector(function, *args, **kw) + else: + return Base(function, *args, **kw) + + + +class FindPathDirs(object): + """ + A class to bind a specific E{*}PATH variable name to a function that + will return all of the E{*}path directories. + """ + def __init__(self, variable): + self.variable = variable + def __call__(self, env, dir=None, target=None, source=None, argument=None): + import SCons.PathList + try: + path = env[self.variable] + except KeyError: + return () + + dir = dir or env.fs._cwd + path = SCons.PathList.PathList(path).subst_path(env, target, source) + return tuple(dir.Rfindalldirs(path)) + + + +class Base(object): + """ + The base class for dependency scanners. This implements + straightforward, single-pass scanning of a single file. + """ + + def __init__(self, + function, + name = "NONE", + argument = _null, + skeys = _null, + path_function = None, + # Node.FS.Base so that, by default, it's okay for a + # scanner to return a Dir, File or Entry. + node_class = SCons.Node.FS.Base, + node_factory = None, + scan_check = None, + recursive = None): + """ + Construct a new scanner object given a scanner function. + + 'function' - a scanner function taking two or three + arguments and returning a list of strings. + + 'name' - a name for identifying this scanner object. + + 'argument' - an optional argument that, if specified, will be + passed to both the scanner function and the path_function. + + 'skeys' - an optional list argument that can be used to determine + which scanner should be used for a given Node. In the case of File + nodes, for example, the 'skeys' would be file suffixes. + + 'path_function' - a function that takes four or five arguments + (a construction environment, Node for the directory containing + the SConscript file that defined the primary target, list of + target nodes, list of source nodes, and optional argument for + this instance) and returns a tuple of the directories that can + be searched for implicit dependency files. May also return a + callable() which is called with no args and returns the tuple + (supporting Bindable class). + + 'node_class' - the class of Nodes which this scan will return. + If node_class is None, then this scanner will not enforce any + Node conversion and will return the raw results from the + underlying scanner function. + + 'node_factory' - the factory function to be called to translate + the raw results returned by the scanner function into the + expected node_class objects. + + 'scan_check' - a function to be called to first check whether + this node really needs to be scanned. + + 'recursive' - specifies that this scanner should be invoked + recursively on all of the implicit dependencies it returns + (the canonical example being #include lines in C source files). + May be a callable, which will be called to filter the list + of nodes found to select a subset for recursive scanning + (the canonical example being only recursively scanning + subdirectories within a directory). + + The scanner function's first argument will be a Node that should + be scanned for dependencies, the second argument will be an + Environment object, the third argument will be the tuple of paths + returned by the path_function, and the fourth argument will be + the value passed into 'argument', and the returned list should + contain the Nodes for all the direct dependencies of the file. + + Examples: + + s = Scanner(my_scanner_function) + + s = Scanner(function = my_scanner_function) + + s = Scanner(function = my_scanner_function, argument = 'foo') + + """ + + # Note: this class could easily work with scanner functions that take + # something other than a filename as an argument (e.g. a database + # node) and a dependencies list that aren't file names. All that + # would need to be changed is the documentation. + + self.function = function + self.path_function = path_function + self.name = name + self.argument = argument + + if skeys is _null: + if SCons.Util.is_Dict(function): + skeys = list(function.keys()) + else: + skeys = [] + self.skeys = skeys + + self.node_class = node_class + self.node_factory = node_factory + self.scan_check = scan_check + if callable(recursive): + self.recurse_nodes = recursive + elif recursive: + self.recurse_nodes = self._recurse_all_nodes + else: + self.recurse_nodes = self._recurse_no_nodes + + def path(self, env, dir=None, target=None, source=None): + if not self.path_function: + return () + if self.argument is not _null: + return self.path_function(env, dir, target, source, self.argument) + else: + return self.path_function(env, dir, target, source) + + def __call__(self, node, env, path=()): + """ + This method scans a single object. 'node' is the node + that will be passed to the scanner function, and 'env' is the + environment that will be passed to the scanner function. A list of + direct dependency nodes for the specified node will be returned. + """ + if self.scan_check and not self.scan_check(node, env): + return [] + + self = self.select(node) + + if not self.argument is _null: + node_list = self.function(node, env, path, self.argument) + else: + node_list = self.function(node, env, path) + + kw = {} + if hasattr(node, 'dir'): + kw['directory'] = node.dir + node_factory = env.get_factory(self.node_factory) + nodes = [] + for l in node_list: + if self.node_class and not isinstance(l, self.node_class): + l = node_factory(l, **kw) + nodes.append(l) + return nodes + + def __eq__(self, other): + try: + return self.__dict__ == other.__dict__ + except AttributeError: + # other probably doesn't have a __dict__ + return self.__dict__ == other + + def __hash__(self): + return id(self) + + def __str__(self): + return self.name + + def add_skey(self, skey): + """Add a skey to the list of skeys""" + self.skeys.append(skey) + + def get_skeys(self, env=None): + if env and SCons.Util.is_String(self.skeys): + return env.subst_list(self.skeys)[0] + return self.skeys + + def select(self, node): + if SCons.Util.is_Dict(self.function): + key = node.scanner_key() + try: + return self.function[key] + except KeyError: + return None + else: + return self + + def _recurse_all_nodes(self, nodes): + return nodes + + def _recurse_no_nodes(self, nodes): + return [] + + # recurse_nodes = _recurse_no_nodes + + def add_scanner(self, skey, scanner): + self.function[skey] = scanner + self.add_skey(skey) + + +class Selector(Base): + """ + A class for selecting a more specific scanner based on the + scanner_key() (suffix) for a specific Node. + + TODO: This functionality has been moved into the inner workings of + the Base class, and this class will be deprecated at some point. + (It was never exposed directly as part of the public interface, + although it is used by the Scanner() factory function that was + used by various Tool modules and therefore was likely a template + for custom modules that may be out there.) + """ + def __init__(self, dict, *args, **kw): + Base.__init__(self, None, *args, **kw) + self.dict = dict + self.skeys = list(dict.keys()) + + def __call__(self, node, env, path=()): + return self.select(node)(node, env, path) + + def select(self, node): + try: + return self.dict[node.scanner_key()] + except KeyError: + return None + + def add_scanner(self, skey, scanner): + self.dict[skey] = scanner + self.add_skey(skey) + + +class Current(Base): + """ + A class for scanning files that are source files (have no builder) + or are derived files and are current (which implies that they exist, + either locally or in a repository). + """ + + def __init__(self, *args, **kw): + def current_check(node, env): + return not node.has_builder() or node.is_up_to_date() + kw['scan_check'] = current_check + Base.__init__(self, *args, **kw) + +class Classic(Current): + """ + A Scanner subclass to contain the common logic for classic CPP-style + include scanning, but which can be customized to use different + regular expressions to find the includes. + + Note that in order for this to work "out of the box" (without + overriding the find_include() and sort_key() methods), the regular + expression passed to the constructor must return the name of the + include file in group 0. + """ + + def __init__(self, name, suffixes, path_variable, regex, *args, **kw): + + self.cre = re.compile(regex, re.M) + + def _scan(node, _, path=(), self=self): + node = node.rfile() + if not node.exists(): + return [] + return self.scan(node, path) + + kw['function'] = _scan + kw['path_function'] = FindPathDirs(path_variable) + + # Allow recursive to propagate if child class specifies. + # In this case resource scanner needs to specify a filter on which files + # get recursively processed. Previously was hardcoded to 1 instead of + # defaulted to 1. + kw['recursive'] = kw.get('recursive', 1) + kw['skeys'] = suffixes + kw['name'] = name + + Current.__init__(self, *args, **kw) + + def find_include(self, include, source_dir, path): + n = SCons.Node.FS.find_file(include, (source_dir,) + tuple(path)) + return n, include + + def sort_key(self, include): + return SCons.Node.FS._my_normcase(include) + + def find_include_names(self, node): + return self.cre.findall(node.get_text_contents()) + + def scan(self, node, path=()): + + # cache the includes list in node so we only scan it once: + if node.includes is not None: + includes = node.includes + else: + includes = self.find_include_names(node) + # Intern the names of the include files. Saves some memory + # if the same header is included many times. + node.includes = list(map(SCons.Util.silent_intern, includes)) + + # This is a hand-coded DSU (decorate-sort-undecorate, or + # Schwartzian transform) pattern. The sort key is the raw name + # of the file as specifed on the #include line (including the + # " or <, since that may affect what file is found), which lets + # us keep the sort order constant regardless of whether the file + # is actually found in a Repository or locally. + nodes = [] + source_dir = node.get_dir() + if callable(path): + path = path() + for include in includes: + n, i = self.find_include(include, source_dir, path) + + if n is None: + SCons.Warnings.warn(SCons.Warnings.DependencyWarning, + "No dependency generated for file: %s (included from: %s) -- file not found" % (i, node)) + else: + nodes.append((self.sort_key(include), n)) + + return [pair[1] for pair in sorted(nodes)] + +class ClassicCPP(Classic): + """ + A Classic Scanner subclass which takes into account the type of + bracketing used to include the file, and uses classic CPP rules + for searching for the files based on the bracketing. + + Note that in order for this to work, the regular expression passed + to the constructor must return the leading bracket in group 0, and + the contained filename in group 1. + """ + def find_include(self, include, source_dir, path): + include = list(map(SCons.Util.to_str, include)) + if include[0] == '"': + paths = (source_dir,) + tuple(path) + else: + paths = tuple(path) + (source_dir,) + + n = SCons.Node.FS.find_file(include[1], paths) + + i = SCons.Util.silent_intern(include[1]) + return n, i + + def sort_key(self, include): + return SCons.Node.FS._my_normcase(' '.join(include)) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Script/Interactive.py b/tools/scons/scons-local-3.0.5/SCons/Script/Interactive.py new file mode 100755 index 0000000000..0e73204b73 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Script/Interactive.py @@ -0,0 +1,376 @@ +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from __future__ import print_function + +__revision__ = "src/engine/SCons/Script/Interactive.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +__doc__ = """ +SCons interactive mode +""" + +# TODO: +# +# This has the potential to grow into something with a really big life +# of its own, which might or might not be a good thing. Nevertheless, +# here are some enhancements that will probably be requested some day +# and are worth keeping in mind (assuming this takes off): +# +# - A command to re-read / re-load the SConscript files. This may +# involve allowing people to specify command-line options (e.g. -f, +# -I, --no-site-dir) that affect how the SConscript files are read. +# +# - Additional command-line options on the "build" command. +# +# Of the supported options that seemed to make sense (after a quick +# pass through the list), the ones that seemed likely enough to be +# used are listed in the man page and have explicit test scripts. +# +# These had code changed in Script/Main.py to support them, but didn't +# seem likely to be used regularly, so had no test scripts added: +# +# build --diskcheck=* +# build --implicit-cache=* +# build --implicit-deps-changed=* +# build --implicit-deps-unchanged=* +# +# These look like they should "just work" with no changes to the +# existing code, but like those above, look unlikely to be used and +# therefore had no test scripts added: +# +# build --random +# +# These I'm not sure about. They might be useful for individual +# "build" commands, and may even work, but they seem unlikely enough +# that we'll wait until they're requested before spending any time on +# writing test scripts for them, or investigating whether they work. +# +# build -q [??? is there a useful analog to the exit status?] +# build --duplicate= +# build --profile= +# build --max-drift= +# build --warn=* +# build --Y +# +# - Most of the SCons command-line options that the "build" command +# supports should be settable as default options that apply to all +# subsequent "build" commands. Maybe a "set {option}" command that +# maps to "SetOption('{option}')". +# +# - Need something in the 'help' command that prints the -h output. +# +# - A command to run the configure subsystem separately (must see how +# this interacts with the new automake model). +# +# - Command-line completion of target names; maybe even of SCons options? +# Completion is something that's supported by the Python cmd module, +# so this should be doable without too much trouble. +# + +import cmd +import copy +import os +import re +import shlex +import sys + +try: + import readline +except ImportError: + pass + +class SConsInteractiveCmd(cmd.Cmd): + """\ + +build [TARGETS] Build the specified TARGETS and their dependencies. 'b' is a synonym. +clean [TARGETS] Clean (remove) the specified TARGETS and their dependencies. 'c' is a synonym. +exit Exit SCons interactive mode. +help [COMMAND] Prints help for the specified COMMAND. 'h' and '?' are synonyms. +shell [COMMANDLINE] Execute COMMANDLINE in a subshell. 'sh' and '!' are synonyms. +version Prints SCons version information. +""" + + synonyms = { + 'b' : 'build', + 'c' : 'clean', + 'h' : 'help', + 'scons' : 'build', + 'sh' : 'shell', + } + + def __init__(self, **kw): + cmd.Cmd.__init__(self) + for key, val in kw.items(): + setattr(self, key, val) + + if sys.platform == 'win32': + self.shell_variable = 'COMSPEC' + else: + self.shell_variable = 'SHELL' + + def default(self, argv): + print("*** Unknown command: %s" % argv[0]) + + def onecmd(self, line): + line = line.strip() + if not line: + print(self.lastcmd) + return self.emptyline() + self.lastcmd = line + if line[0] == '!': + line = 'shell ' + line[1:] + elif line[0] == '?': + line = 'help ' + line[1:] + if os.sep == '\\': + line = line.replace('\\', '\\\\') + argv = shlex.split(line) + argv[0] = self.synonyms.get(argv[0], argv[0]) + if not argv[0]: + return self.default(line) + else: + try: + func = getattr(self, 'do_' + argv[0]) + except AttributeError: + return self.default(argv) + return func(argv) + + def do_build(self, argv): + """\ + build [TARGETS] Build the specified TARGETS and their + dependencies. 'b' is a synonym. + """ + import SCons.Node + import SCons.SConsign + import SCons.Script.Main + + options = copy.deepcopy(self.options) + + options, targets = self.parser.parse_args(argv[1:], values=options) + + SCons.Script.COMMAND_LINE_TARGETS = targets + + if targets: + SCons.Script.BUILD_TARGETS = targets + else: + # If the user didn't specify any targets on the command line, + # use the list of default targets. + SCons.Script.BUILD_TARGETS = SCons.Script._build_plus_default + + nodes = SCons.Script.Main._build_targets(self.fs, + options, + targets, + self.target_top) + + if not nodes: + return + + # Call each of the Node's alter_targets() methods, which may + # provide additional targets that ended up as part of the build + # (the canonical example being a VariantDir() when we're building + # from a source directory) and which we therefore need their + # state cleared, too. + x = [] + for n in nodes: + x.extend(n.alter_targets()[0]) + nodes.extend(x) + + # Clean up so that we can perform the next build correctly. + # + # We do this by walking over all the children of the targets, + # and clearing their state. + # + # We currently have to re-scan each node to find their + # children, because built nodes have already been partially + # cleared and don't remember their children. (In scons + # 0.96.1 and earlier, this wasn't the case, and we didn't + # have to re-scan the nodes.) + # + # Because we have to re-scan each node, we can't clear the + # nodes as we walk over them, because we may end up rescanning + # a cleared node as we scan a later node. Therefore, only + # store the list of nodes that need to be cleared as we walk + # the tree, and clear them in a separate pass. + # + # XXX: Someone more familiar with the inner workings of scons + # may be able to point out a more efficient way to do this. + + SCons.Script.Main.progress_display("scons: Clearing cached node information ...") + + seen_nodes = {} + + def get_unseen_children(node, parent, seen_nodes=seen_nodes): + def is_unseen(node, seen_nodes=seen_nodes): + return node not in seen_nodes + return [child for child in node.children(scan=1) if is_unseen(child)] + + def add_to_seen_nodes(node, parent, seen_nodes=seen_nodes): + seen_nodes[node] = 1 + + # If this file is in a VariantDir and has a + # corresponding source file in the source tree, remember the + # node in the source tree, too. This is needed in + # particular to clear cached implicit dependencies on the + # source file, since the scanner will scan it if the + # VariantDir was created with duplicate=0. + try: + rfile_method = node.rfile + except AttributeError: + return + else: + rfile = rfile_method() + if rfile != node: + seen_nodes[rfile] = 1 + + for node in nodes: + walker = SCons.Node.Walker(node, + kids_func=get_unseen_children, + eval_func=add_to_seen_nodes) + n = walker.get_next() + while n: + n = walker.get_next() + + for node in list(seen_nodes.keys()): + # Call node.clear() to clear most of the state + node.clear() + # node.clear() doesn't reset node.state, so call + # node.set_state() to reset it manually + node.set_state(SCons.Node.no_state) + node.implicit = None + + # Debug: Uncomment to verify that all Taskmaster reference + # counts have been reset to zero. + #if node.ref_count != 0: + # from SCons.Debug import Trace + # Trace('node %s, ref_count %s !!!\n' % (node, node.ref_count)) + + SCons.SConsign.Reset() + SCons.Script.Main.progress_display("scons: done clearing node information.") + + def do_clean(self, argv): + """\ + clean [TARGETS] Clean (remove) the specified TARGETS + and their dependencies. 'c' is a synonym. + """ + return self.do_build(['build', '--clean'] + argv[1:]) + + def do_EOF(self, argv): + print() + self.do_exit(argv) + + def _do_one_help(self, arg): + try: + # If help_() exists, then call it. + func = getattr(self, 'help_' + arg) + except AttributeError: + try: + func = getattr(self, 'do_' + arg) + except AttributeError: + doc = None + else: + doc = self._doc_to_help(func) + if doc: + sys.stdout.write(doc + '\n') + sys.stdout.flush() + else: + doc = self.strip_initial_spaces(func()) + if doc: + sys.stdout.write(doc + '\n') + sys.stdout.flush() + + def _doc_to_help(self, obj): + doc = obj.__doc__ + if doc is None: + return '' + return self._strip_initial_spaces(doc) + + def _strip_initial_spaces(self, s): + lines = s.split('\n') + spaces = re.match(' *', lines[0]).group(0) + def strip_spaces(l, spaces=spaces): + if l[:len(spaces)] == spaces: + l = l[len(spaces):] + return l + lines = list(map(strip_spaces, lines)) + return '\n'.join(lines) + + def do_exit(self, argv): + """\ + exit Exit SCons interactive mode. + """ + sys.exit(0) + + def do_help(self, argv): + """\ + help [COMMAND] Prints help for the specified COMMAND. 'h' + and '?' are synonyms. + """ + if argv[1:]: + for arg in argv[1:]: + if self._do_one_help(arg): + break + else: + # If bare 'help' is called, print this class's doc + # string (if it has one). + doc = self._doc_to_help(self.__class__) + if doc: + sys.stdout.write(doc + '\n') + sys.stdout.flush() + + def do_shell(self, argv): + """\ + shell [COMMANDLINE] Execute COMMANDLINE in a subshell. 'sh' and + '!' are synonyms. + """ + import subprocess + argv = argv[1:] + if not argv: + argv = os.environ[self.shell_variable] + try: + # Per "[Python-Dev] subprocess insufficiently platform-independent?" + # http://mail.python.org/pipermail/python-dev/2008-August/081979.html "+ + # Doing the right thing with an argument list currently + # requires different shell= values on Windows and Linux. + p = subprocess.Popen(argv, shell=(sys.platform=='win32')) + except EnvironmentError as e: + sys.stderr.write('scons: %s: %s\n' % (argv[0], e.strerror)) + else: + p.wait() + + def do_version(self, argv): + """\ + version Prints SCons version information. + """ + sys.stdout.write(self.parser.version + '\n') + +def interact(fs, parser, options, targets, target_top): + c = SConsInteractiveCmd(prompt = 'scons>>> ', + fs = fs, + parser = parser, + options = options, + targets = targets, + target_top = target_top) + c.cmdloop() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Script/Main.py b/tools/scons/scons-local-3.0.5/SCons/Script/Main.py new file mode 100755 index 0000000000..c6779376ab --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Script/Main.py @@ -0,0 +1,1440 @@ +"""SCons.Script + +This file implements the main() function used by the scons script. + +Architecturally, this *is* the scons script, and will likely only be +called from the external "scons" wrapper. Consequently, anything here +should not be, or be considered, part of the build engine. If it's +something that we expect other software to want to use, it should go in +some other module. If it's specific to the "scons" script invocation, +it goes here. +""" + +from __future__ import print_function + + +unsupported_python_version = (2, 6, 0) +deprecated_python_version = (2, 7, 0) + + +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +__revision__ = "src/engine/SCons/Script/Main.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + + +import SCons.compat + +import os +import sys +import time +import traceback +import sysconfig +import platform + +import SCons.CacheDir +import SCons.Debug +import SCons.Defaults +import SCons.Environment +import SCons.Errors +import SCons.Job +import SCons.Node +import SCons.Node.FS +import SCons.Platform +import SCons.Platform.virtualenv +import SCons.SConf +import SCons.Script +import SCons.Taskmaster +import SCons.Util +import SCons.Warnings + +import SCons.Script.Interactive + + +def fetch_win32_parallel_msg(): + # A subsidiary function that exists solely to isolate this import + # so we don't have to pull it in on all platforms, and so that an + # in-line "import" statement in the _main() function below doesn't + # cause warnings about local names shadowing use of the 'SCons' + # global in nest scopes and UnboundLocalErrors and the like in some + # versions (2.1) of Python. + import SCons.Platform.win32 + return SCons.Platform.win32.parallel_msg + + +def revert_io(): + # This call is added to revert stderr and stdout to the original + # ones just in case some build rule or something else in the system + # has redirected them elsewhere. + sys.stderr = sys.__stderr__ + sys.stdout = sys.__stdout__ + +class SConsPrintHelpException(Exception): + pass + +display = SCons.Util.display +progress_display = SCons.Util.DisplayEngine() + +first_command_start = None +last_command_end = None + + +class Progressor(object): + prev = '' + count = 0 + target_string = '$TARGET' + + def __init__(self, obj, interval=1, file=None, overwrite=False): + if file is None: + file = sys.stdout + + self.obj = obj + self.file = file + self.interval = interval + self.overwrite = overwrite + + if callable(obj): + self.func = obj + elif SCons.Util.is_List(obj): + self.func = self.spinner + elif obj.find(self.target_string) != -1: + self.func = self.replace_string + else: + self.func = self.string + + def write(self, s): + self.file.write(s) + self.file.flush() + self.prev = s + + def erase_previous(self): + if self.prev: + length = len(self.prev) + if self.prev[-1] in ('\n', '\r'): + length = length - 1 + self.write(' ' * length + '\r') + self.prev = '' + + def spinner(self, node): + self.write(self.obj[self.count % len(self.obj)]) + + def string(self, node): + self.write(self.obj) + + def replace_string(self, node): + self.write(self.obj.replace(self.target_string, str(node))) + + def __call__(self, node): + self.count = self.count + 1 + if (self.count % self.interval) == 0: + if self.overwrite: + self.erase_previous() + self.func(node) + +ProgressObject = SCons.Util.Null() + +def Progress(*args, **kw): + global ProgressObject + ProgressObject = Progressor(*args, **kw) + +# Task control. +# + +_BuildFailures = [] + + +def GetBuildFailures(): + return _BuildFailures + + +class BuildTask(SCons.Taskmaster.OutOfDateTask): + """An SCons build task.""" + progress = ProgressObject + + def display(self, message): + display('scons: ' + message) + + def prepare(self): + self.progress(self.targets[0]) + return SCons.Taskmaster.OutOfDateTask.prepare(self) + + def needs_execute(self): + if SCons.Taskmaster.OutOfDateTask.needs_execute(self): + return True + if self.top and self.targets[0].has_builder(): + display("scons: `%s' is up to date." % str(self.node)) + return False + + def execute(self): + if print_time: + start_time = time.time() + global first_command_start + if first_command_start is None: + first_command_start = start_time + SCons.Taskmaster.OutOfDateTask.execute(self) + if print_time: + global cumulative_command_time + global last_command_end + finish_time = time.time() + last_command_end = finish_time + cumulative_command_time = cumulative_command_time+finish_time-start_time + sys.stdout.write("Command execution time: %s: %f seconds\n"%(str(self.node), finish_time-start_time)) + + def do_failed(self, status=2): + _BuildFailures.append(self.exception[1]) + global exit_status + global this_build_status + if self.options.ignore_errors: + SCons.Taskmaster.OutOfDateTask.executed(self) + elif self.options.keep_going: + SCons.Taskmaster.OutOfDateTask.fail_continue(self) + exit_status = status + this_build_status = status + else: + SCons.Taskmaster.OutOfDateTask.fail_stop(self) + exit_status = status + this_build_status = status + + def executed(self): + t = self.targets[0] + if self.top and not t.has_builder() and not t.side_effect: + if not t.exists(): + if t.__class__.__name__ in ('File', 'Dir', 'Entry'): + errstr="Do not know how to make %s target `%s' (%s)." % (t.__class__.__name__, t, t.get_abspath()) + else: # Alias or Python or ... + errstr="Do not know how to make %s target `%s'." % (t.__class__.__name__, t) + sys.stderr.write("scons: *** " + errstr) + if not self.options.keep_going: + sys.stderr.write(" Stop.") + sys.stderr.write("\n") + try: + raise SCons.Errors.BuildError(t, errstr) + except KeyboardInterrupt: + raise + except: + self.exception_set() + self.do_failed() + else: + print("scons: Nothing to be done for `%s'." % t) + SCons.Taskmaster.OutOfDateTask.executed(self) + else: + SCons.Taskmaster.OutOfDateTask.executed(self) + + def failed(self): + # Handle the failure of a build task. The primary purpose here + # is to display the various types of Errors and Exceptions + # appropriately. + exc_info = self.exc_info() + try: + t, e, tb = exc_info + except ValueError: + t, e = exc_info + tb = None + + if t is None: + # The Taskmaster didn't record an exception for this Task; + # see if the sys module has one. + try: + t, e, tb = sys.exc_info()[:] + except ValueError: + t, e = exc_info + tb = None + + # Deprecated string exceptions will have their string stored + # in the first entry of the tuple. + if e is None: + e = t + + buildError = SCons.Errors.convert_to_BuildError(e) + if not buildError.node: + buildError.node = self.node + + node = buildError.node + if not SCons.Util.is_List(node): + node = [ node ] + nodename = ', '.join(map(str, node)) + + errfmt = "scons: *** [%s] %s\n" + sys.stderr.write(errfmt % (nodename, buildError)) + + if (buildError.exc_info[2] and buildError.exc_info[1] and + not isinstance( + buildError.exc_info[1], + (EnvironmentError, SCons.Errors.StopError, + SCons.Errors.UserError))): + type, value, trace = buildError.exc_info + if tb and print_stacktrace: + sys.stderr.write("scons: internal stack trace:\n") + traceback.print_tb(tb, file=sys.stderr) + traceback.print_exception(type, value, trace) + elif tb and print_stacktrace: + sys.stderr.write("scons: internal stack trace:\n") + traceback.print_tb(tb, file=sys.stderr) + + self.exception = (e, buildError, tb) # type, value, traceback + self.do_failed(buildError.exitstatus) + + self.exc_clear() + + def postprocess(self): + if self.top: + t = self.targets[0] + for tp in self.options.tree_printers: + tp.display(t) + if self.options.debug_includes: + tree = t.render_include_tree() + if tree: + print() + print(tree) + SCons.Taskmaster.OutOfDateTask.postprocess(self) + + def make_ready(self): + """Make a task ready for execution""" + SCons.Taskmaster.OutOfDateTask.make_ready(self) + if self.out_of_date and self.options.debug_explain: + explanation = self.out_of_date[0].explain() + if explanation: + sys.stdout.write("scons: " + explanation) + + +class CleanTask(SCons.Taskmaster.AlwaysTask): + """An SCons clean task.""" + def fs_delete(self, path, pathstr, remove=True): + try: + if os.path.lexists(path): + if os.path.isfile(path) or os.path.islink(path): + if remove: os.unlink(path) + display("Removed " + pathstr) + elif os.path.isdir(path) and not os.path.islink(path): + # delete everything in the dir + for e in sorted(os.listdir(path)): + p = os.path.join(path, e) + s = os.path.join(pathstr, e) + if os.path.isfile(p): + if remove: os.unlink(p) + display("Removed " + s) + else: + self.fs_delete(p, s, remove) + # then delete dir itself + if remove: os.rmdir(path) + display("Removed directory " + pathstr) + else: + errstr = "Path '%s' exists but isn't a file or directory." + raise SCons.Errors.UserError(errstr % (pathstr)) + except SCons.Errors.UserError as e: + print(e) + except (IOError, OSError) as e: + print("scons: Could not remove '%s':" % pathstr, e.strerror) + + def _get_files_to_clean(self): + result = [] + target = self.targets[0] + if target.has_builder() or target.side_effect: + result = [t for t in self.targets if not t.noclean] + return result + + def _clean_targets(self, remove=True): + target = self.targets[0] + if target in SCons.Environment.CleanTargets: + files = SCons.Environment.CleanTargets[target] + for f in files: + self.fs_delete(f.get_abspath(), str(f), remove) + + def show(self): + for t in self._get_files_to_clean(): + if not t.isdir(): + display("Removed " + str(t)) + self._clean_targets(remove=False) + + def remove(self): + for t in self._get_files_to_clean(): + try: + removed = t.remove() + except OSError as e: + # An OSError may indicate something like a permissions + # issue, an IOError would indicate something like + # the file not existing. In either case, print a + # message and keep going to try to remove as many + # targets as possible. + print("scons: Could not remove '{0}'".format(str(t)), e.strerror) + else: + if removed: + display("Removed " + str(t)) + self._clean_targets(remove=True) + + execute = remove + + # We want the Taskmaster to update the Node states (and therefore + # handle reference counts, etc.), but we don't want to call + # back to the Node's post-build methods, which would do things + # we don't want, like store .sconsign information. + executed = SCons.Taskmaster.Task.executed_without_callbacks + + # Have the Taskmaster arrange to "execute" all of the targets, because + # we'll figure out ourselves (in remove() or show() above) whether + # anything really needs to be done. + make_ready = SCons.Taskmaster.Task.make_ready_all + + def prepare(self): + pass + +class QuestionTask(SCons.Taskmaster.AlwaysTask): + """An SCons task for the -q (question) option.""" + def prepare(self): + pass + + def execute(self): + if self.targets[0].get_state() != SCons.Node.up_to_date or \ + (self.top and not self.targets[0].exists()): + global exit_status + global this_build_status + exit_status = 1 + this_build_status = 1 + self.tm.stop() + + def executed(self): + pass + + +class TreePrinter(object): + def __init__(self, derived=False, prune=False, status=False): + self.derived = derived + self.prune = prune + self.status = status + def get_all_children(self, node): + return node.all_children() + def get_derived_children(self, node): + children = node.all_children(None) + return [x for x in children if x.has_builder()] + def display(self, t): + if self.derived: + func = self.get_derived_children + else: + func = self.get_all_children + s = self.status and 2 or 0 + SCons.Util.print_tree(t, func, prune=self.prune, showtags=s) + + +def python_version_string(): + return sys.version.split()[0] + +def python_version_unsupported(version=sys.version_info): + return version < unsupported_python_version + +def python_version_deprecated(version=sys.version_info): + return version < deprecated_python_version + + +# Global variables + +print_objects = 0 +print_memoizer = 0 +print_stacktrace = 0 +print_time = 0 +sconscript_time = 0 +cumulative_command_time = 0 +exit_status = 0 # final exit status, assume success by default +this_build_status = 0 # "exit status" of an individual build +num_jobs = None +delayed_warnings = [] + +class FakeOptionParser(object): + """ + A do-nothing option parser, used for the initial OptionsParser variable. + + During normal SCons operation, the OptionsParser is created right + away by the main() function. Certain tests scripts however, can + introspect on different Tool modules, the initialization of which + can try to add a new, local option to an otherwise uninitialized + OptionsParser object. This allows that introspection to happen + without blowing up. + + """ + class FakeOptionValues(object): + def __getattr__(self, attr): + return None + values = FakeOptionValues() + def add_local_option(self, *args, **kw): + pass + +OptionsParser = FakeOptionParser() + +def AddOption(*args, **kw): + if 'default' not in kw: + kw['default'] = None + result = OptionsParser.add_local_option(*args, **kw) + return result + +def GetOption(name): + return getattr(OptionsParser.values, name) + +def SetOption(name, value): + return OptionsParser.values.set_option(name, value) + +def PrintHelp(file=None): + OptionsParser.print_help(file=file) + +class Stats(object): + def __init__(self): + self.stats = [] + self.labels = [] + self.append = self.do_nothing + self.print_stats = self.do_nothing + def enable(self, outfp): + self.outfp = outfp + self.append = self.do_append + self.print_stats = self.do_print + def do_nothing(self, *args, **kw): + pass + +class CountStats(Stats): + def do_append(self, label): + self.labels.append(label) + self.stats.append(SCons.Debug.fetchLoggedInstances()) + def do_print(self): + stats_table = {} + for s in self.stats: + for n in [t[0] for t in s]: + stats_table[n] = [0, 0, 0, 0] + i = 0 + for s in self.stats: + for n, c in s: + stats_table[n][i] = c + i = i + 1 + self.outfp.write("Object counts:\n") + pre = [" "] + post = [" %s\n"] + l = len(self.stats) + fmt1 = ''.join(pre + [' %7s']*l + post) + fmt2 = ''.join(pre + [' %7d']*l + post) + labels = self.labels[:l] + labels.append(("", "Class")) + self.outfp.write(fmt1 % tuple([x[0] for x in labels])) + self.outfp.write(fmt1 % tuple([x[1] for x in labels])) + for k in sorted(stats_table.keys()): + r = stats_table[k][:l] + [k] + self.outfp.write(fmt2 % tuple(r)) + +count_stats = CountStats() + +class MemStats(Stats): + def do_append(self, label): + self.labels.append(label) + self.stats.append(SCons.Debug.memory()) + def do_print(self): + fmt = 'Memory %-32s %12d\n' + for label, stats in zip(self.labels, self.stats): + self.outfp.write(fmt % (label, stats)) + +memory_stats = MemStats() + +# utility functions + +def _scons_syntax_error(e): + """Handle syntax errors. Print out a message and show where the error + occurred. + """ + etype, value, tb = sys.exc_info() + lines = traceback.format_exception_only(etype, value) + for line in lines: + sys.stderr.write(line+'\n') + sys.exit(2) + +def find_deepest_user_frame(tb): + """ + Find the deepest stack frame that is not part of SCons. + + Input is a "pre-processed" stack trace in the form + returned by traceback.extract_tb() or traceback.extract_stack() + """ + + tb.reverse() + + # find the deepest traceback frame that is not part + # of SCons: + for frame in tb: + filename = frame[0] + if filename.find(os.sep+'SCons'+os.sep) == -1: + return frame + return tb[0] + +def _scons_user_error(e): + """Handle user errors. Print out a message and a description of the + error, along with the line number and routine where it occured. + The file and line number will be the deepest stack frame that is + not part of SCons itself. + """ + global print_stacktrace + etype, value, tb = sys.exc_info() + if print_stacktrace: + traceback.print_exception(etype, value, tb) + filename, lineno, routine, dummy = find_deepest_user_frame(traceback.extract_tb(tb)) + sys.stderr.write("\nscons: *** %s\n" % value) + sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine)) + sys.exit(2) + +def _scons_user_warning(e): + """Handle user warnings. Print out a message and a description of + the warning, along with the line number and routine where it occured. + The file and line number will be the deepest stack frame that is + not part of SCons itself. + """ + etype, value, tb = sys.exc_info() + filename, lineno, routine, dummy = find_deepest_user_frame(traceback.extract_tb(tb)) + sys.stderr.write("\nscons: warning: %s\n" % e) + sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine)) + +def _scons_internal_warning(e): + """Slightly different from _scons_user_warning in that we use the + *current call stack* rather than sys.exc_info() to get our stack trace. + This is used by the warnings framework to print warnings.""" + filename, lineno, routine, dummy = find_deepest_user_frame(traceback.extract_stack()) + sys.stderr.write("\nscons: warning: %s\n" % e.args[0]) + sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine)) + +def _scons_internal_error(): + """Handle all errors but user errors. Print out a message telling + the user what to do in this case and print a normal trace. + """ + print('internal error') + traceback.print_exc() + sys.exit(2) + +def _SConstruct_exists(dirname='', repositories=[], filelist=None): + """This function checks that an SConstruct file exists in a directory. + If so, it returns the path of the file. By default, it checks the + current directory. + """ + if not filelist: + filelist = ['SConstruct', 'Sconstruct', 'sconstruct', 'SConstruct.py', 'Sconstruct.py', 'sconstruct.py'] + for file in filelist: + sfile = os.path.join(dirname, file) + if os.path.isfile(sfile): + return sfile + if not os.path.isabs(sfile): + for rep in repositories: + if os.path.isfile(os.path.join(rep, sfile)): + return sfile + return None + +def _set_debug_values(options): + global print_memoizer, print_objects, print_stacktrace, print_time + + debug_values = options.debug + + if "count" in debug_values: + # All of the object counts are within "if track_instances:" blocks, + # which get stripped when running optimized (with python -O or + # from compiled *.pyo files). Provide a warning if __debug__ is + # stripped, so it doesn't just look like --debug=count is broken. + enable_count = False + if __debug__: enable_count = True + if enable_count: + count_stats.enable(sys.stdout) + SCons.Debug.track_instances = True + else: + msg = "--debug=count is not supported when running SCons\n" + \ + "\twith the python -O option or optimized (.pyo) modules." + SCons.Warnings.warn(SCons.Warnings.NoObjectCountWarning, msg) + if "dtree" in debug_values: + options.tree_printers.append(TreePrinter(derived=True)) + options.debug_explain = ("explain" in debug_values) + if "findlibs" in debug_values: + SCons.Scanner.Prog.print_find_libs = "findlibs" + options.debug_includes = ("includes" in debug_values) + print_memoizer = ("memoizer" in debug_values) + if "memory" in debug_values: + memory_stats.enable(sys.stdout) + print_objects = ("objects" in debug_values) + if print_objects: + SCons.Debug.track_instances = True + if "presub" in debug_values: + SCons.Action.print_actions_presub = 1 + if "stacktrace" in debug_values: + print_stacktrace = 1 + if "stree" in debug_values: + options.tree_printers.append(TreePrinter(status=True)) + if "time" in debug_values: + print_time = 1 + if "tree" in debug_values: + options.tree_printers.append(TreePrinter()) + if "prepare" in debug_values: + SCons.Taskmaster.print_prepare = 1 + if "duplicate" in debug_values: + SCons.Node.print_duplicate = 1 + +def _create_path(plist): + path = '.' + for d in plist: + if os.path.isabs(d): + path = d + else: + path = path + '/' + d + return path + +def _load_site_scons_dir(topdir, site_dir_name=None): + """Load the site_scons dir under topdir. + Prepends site_scons to sys.path, imports site_scons/site_init.py, + and prepends site_scons/site_tools to default toolpath.""" + if site_dir_name: + err_if_not_found = True # user specified: err if missing + else: + site_dir_name = "site_scons" + err_if_not_found = False + + site_dir = os.path.join(topdir, site_dir_name) + if not os.path.exists(site_dir): + if err_if_not_found: + raise SCons.Errors.UserError("site dir %s not found."%site_dir) + return + + site_init_filename = "site_init.py" + site_init_modname = "site_init" + site_tools_dirname = "site_tools" + # prepend to sys.path + sys.path = [os.path.abspath(site_dir)] + sys.path + site_init_file = os.path.join(site_dir, site_init_filename) + site_tools_dir = os.path.join(site_dir, site_tools_dirname) + if os.path.exists(site_init_file): + import imp, re + try: + try: + fp, pathname, description = imp.find_module(site_init_modname, + [site_dir]) + # Load the file into SCons.Script namespace. This is + # opaque and clever; m is the module object for the + # SCons.Script module, and the exec ... in call executes a + # file (or string containing code) in the context of the + # module's dictionary, so anything that code defines ends + # up adding to that module. This is really short, but all + # the error checking makes it longer. + try: + m = sys.modules['SCons.Script'] + except Exception as e: + fmt = 'cannot import site_init.py: missing SCons.Script module %s' + raise SCons.Errors.InternalError(fmt % repr(e)) + try: + sfx = description[0] + modname = os.path.basename(pathname)[:-len(sfx)] + site_m = {"__file__": pathname, "__name__": modname, "__doc__": None} + re_special = re.compile("__[^_]+__") + for k in list(m.__dict__.keys()): + if not re_special.match(k): + site_m[k] = m.__dict__[k] + + # This is the magic. + exec(compile(fp.read(), fp.name, 'exec'), site_m) + except KeyboardInterrupt: + raise + except Exception as e: + fmt = '*** Error loading site_init file %s:\n' + sys.stderr.write(fmt % repr(site_init_file)) + raise + else: + for k in site_m: + if not re_special.match(k): + m.__dict__[k] = site_m[k] + except KeyboardInterrupt: + raise + except ImportError as e: + fmt = '*** cannot import site init file %s:\n' + sys.stderr.write(fmt % repr(site_init_file)) + raise + finally: + if fp: + fp.close() + if os.path.exists(site_tools_dir): + # prepend to DefaultToolpath + SCons.Tool.DefaultToolpath.insert(0, os.path.abspath(site_tools_dir)) + +def _load_all_site_scons_dirs(topdir, verbose=None): + """Load all of the predefined site_scons dir. + Order is significant; we load them in order from most generic + (machine-wide) to most specific (topdir). + The verbose argument is only for testing. + """ + platform = SCons.Platform.platform_default() + + def homedir(d): + return os.path.expanduser('~/'+d) + + if platform == 'win32' or platform == 'cygwin': + # Note we use $ here instead of %...% because older + # pythons (prior to 2.6?) didn't expand %...% on Windows. + # This set of dirs should work on XP, Vista, 7 and later. + sysdirs=[ + os.path.expandvars('$ALLUSERSPROFILE\\Application Data\\scons'), + os.path.expandvars('$USERPROFILE\\Local Settings\\Application Data\\scons')] + appdatadir = os.path.expandvars('$APPDATA\\scons') + if appdatadir not in sysdirs: + sysdirs.append(appdatadir) + sysdirs.append(homedir('.scons')) + + elif platform == 'darwin': # MacOS X + sysdirs=['/Library/Application Support/SCons', + '/opt/local/share/scons', # (for MacPorts) + '/sw/share/scons', # (for Fink) + homedir('Library/Application Support/SCons'), + homedir('.scons')] + elif platform == 'sunos': # Solaris + sysdirs=['/opt/sfw/scons', + '/usr/share/scons', + homedir('.scons')] + else: # Linux, HPUX, etc. + # assume posix-like, i.e. platform == 'posix' + sysdirs=['/usr/share/scons', + homedir('.scons')] + + dirs=sysdirs + [topdir] + for d in dirs: + if verbose: # this is used by unit tests. + print("Loading site dir ", d) + _load_site_scons_dir(d) + +def test_load_all_site_scons_dirs(d): + _load_all_site_scons_dirs(d, True) + +def version_string(label, module): + version = module.__version__ + build = module.__build__ + if build: + if build[0] != '.': + build = '.' + build + version = version + build + fmt = "\t%s: v%s, %s, by %s on %s\n" + return fmt % (label, + version, + module.__date__, + module.__developer__, + module.__buildsys__) + +def path_string(label, module): + path = module.__path__ + return "\t%s path: %s\n"%(label,path) + +def _main(parser): + global exit_status + global this_build_status + + options = parser.values + + # Here's where everything really happens. + + # First order of business: set up default warnings and then + # handle the user's warning options, so that we can issue (or + # suppress) appropriate warnings about anything that might happen, + # as configured by the user. + + default_warnings = [ SCons.Warnings.WarningOnByDefault, + SCons.Warnings.DeprecatedWarning, + ] + + for warning in default_warnings: + SCons.Warnings.enableWarningClass(warning) + SCons.Warnings._warningOut = _scons_internal_warning + SCons.Warnings.process_warn_strings(options.warn) + + # Now that we have the warnings configuration set up, we can actually + # issue (or suppress) any warnings about warning-worthy things that + # occurred while the command-line options were getting parsed. + try: + dw = options.delayed_warnings + except AttributeError: + pass + else: + delayed_warnings.extend(dw) + for warning_type, message in delayed_warnings: + SCons.Warnings.warn(warning_type, message) + + if not SCons.Platform.virtualenv.virtualenv_enabled_by_default: + if options.enable_virtualenv: + SCons.Platform.virtualenv.enable_virtualenv = True + + if options.ignore_virtualenv: + SCons.Platform.virtualenv.ignore_virtualenv = True + + if options.diskcheck: + SCons.Node.FS.set_diskcheck(options.diskcheck) + + # Next, we want to create the FS object that represents the outside + # world's file system, as that's central to a lot of initialization. + # To do this, however, we need to be in the directory from which we + # want to start everything, which means first handling any relevant + # options that might cause us to chdir somewhere (-C, -D, -U, -u). + if options.directory: + script_dir = os.path.abspath(_create_path(options.directory)) + else: + script_dir = os.getcwd() + + target_top = None + if options.climb_up: + target_top = '.' # directory to prepend to targets + while script_dir and not _SConstruct_exists(script_dir, + options.repository, + options.file): + script_dir, last_part = os.path.split(script_dir) + if last_part: + target_top = os.path.join(last_part, target_top) + else: + script_dir = '' + + if script_dir and script_dir != os.getcwd(): + if not options.silent: + display("scons: Entering directory `%s'" % script_dir) + try: + os.chdir(script_dir) + except OSError: + sys.stderr.write("Could not change directory to %s\n" % script_dir) + + # Now that we're in the top-level SConstruct directory, go ahead + # and initialize the FS object that represents the file system, + # and make it the build engine default. + fs = SCons.Node.FS.get_default_fs() + + for rep in options.repository: + fs.Repository(rep) + + # Now that we have the FS object, the next order of business is to + # check for an SConstruct file (or other specified config file). + # If there isn't one, we can bail before doing any more work. + scripts = [] + if options.file: + scripts.extend(options.file) + if not scripts: + sfile = _SConstruct_exists(repositories=options.repository, + filelist=options.file) + if sfile: + scripts.append(sfile) + + if not scripts: + if options.help: + # There's no SConstruct, but they specified -h. + # Give them the options usage now, before we fail + # trying to read a non-existent SConstruct file. + raise SConsPrintHelpException + raise SCons.Errors.UserError("No SConstruct file found.") + + if scripts[0] == "-": + d = fs.getcwd() + else: + d = fs.File(scripts[0]).dir + fs.set_SConstruct_dir(d) + + _set_debug_values(options) + SCons.Node.implicit_cache = options.implicit_cache + SCons.Node.implicit_deps_changed = options.implicit_deps_changed + SCons.Node.implicit_deps_unchanged = options.implicit_deps_unchanged + + if options.no_exec: + SCons.SConf.dryrun = 1 + SCons.Action.execute_actions = None + if options.question: + SCons.SConf.dryrun = 1 + if options.clean: + SCons.SConf.SetBuildType('clean') + if options.help: + SCons.SConf.SetBuildType('help') + SCons.SConf.SetCacheMode(options.config) + SCons.SConf.SetProgressDisplay(progress_display) + + if options.no_progress or options.silent: + progress_display.set_mode(0) + + if options.site_dir: + _load_site_scons_dir(d.get_internal_path(), options.site_dir) + elif not options.no_site_dir: + _load_all_site_scons_dirs(d.get_internal_path()) + + if options.include_dir: + sys.path = options.include_dir + sys.path + + # If we're about to start SCons in the interactive mode, + # inform the FS about this right here. Else, the release_target_info + # method could get called on some nodes, like the used "gcc" compiler, + # when using the Configure methods within the SConscripts. + # This would then cause subtle bugs, as already happened in #2971. + if options.interactive: + SCons.Node.interactive = True + + # That should cover (most of) the options. Next, set up the variables + # that hold command-line arguments, so the SConscript files that we + # read and execute have access to them. + targets = [] + xmit_args = [] + for a in parser.largs: + if a[:1] == '-': + continue + if '=' in a: + xmit_args.append(a) + else: + targets.append(a) + SCons.Script._Add_Targets(targets + parser.rargs) + SCons.Script._Add_Arguments(xmit_args) + + # If stdout is not a tty, replace it with a wrapper object to call flush + # after every write. + # + # Tty devices automatically flush after every newline, so the replacement + # isn't necessary. Furthermore, if we replace sys.stdout, the readline + # module will no longer work. This affects the behavior during + # --interactive mode. --interactive should only be used when stdin and + # stdout refer to a tty. + if not hasattr(sys.stdout, 'isatty') or not sys.stdout.isatty(): + sys.stdout = SCons.Util.Unbuffered(sys.stdout) + if not hasattr(sys.stderr, 'isatty') or not sys.stderr.isatty(): + sys.stderr = SCons.Util.Unbuffered(sys.stderr) + + memory_stats.append('before reading SConscript files:') + count_stats.append(('pre-', 'read')) + + # And here's where we (finally) read the SConscript files. + + progress_display("scons: Reading SConscript files ...") + + start_time = time.time() + try: + for script in scripts: + SCons.Script._SConscript._SConscript(fs, script) + except SCons.Errors.StopError as e: + # We had problems reading an SConscript file, such as it + # couldn't be copied in to the VariantDir. Since we're just + # reading SConscript files and haven't started building + # things yet, stop regardless of whether they used -i or -k + # or anything else. + revert_io() + sys.stderr.write("scons: *** %s Stop.\n" % e) + sys.exit(2) + global sconscript_time + sconscript_time = time.time() - start_time + + progress_display("scons: done reading SConscript files.") + + memory_stats.append('after reading SConscript files:') + count_stats.append(('post-', 'read')) + + # Re-{enable,disable} warnings in case they disabled some in + # the SConscript file. + # + # We delay enabling the PythonVersionWarning class until here so that, + # if they explicitly disabled it in either in the command line or in + # $SCONSFLAGS, or in the SConscript file, then the search through + # the list of deprecated warning classes will find that disabling + # first and not issue the warning. + #SCons.Warnings.enableWarningClass(SCons.Warnings.PythonVersionWarning) + SCons.Warnings.process_warn_strings(options.warn) + + # Now that we've read the SConscript files, we can check for the + # warning about deprecated Python versions--delayed until here + # in case they disabled the warning in the SConscript files. + if python_version_deprecated(): + msg = "Support for pre-%s Python version (%s) is deprecated.\n" + \ + " If this will cause hardship, contact scons-dev@scons.org" + deprecated_version_string = ".".join(map(str, deprecated_python_version)) + SCons.Warnings.warn(SCons.Warnings.PythonVersionWarning, + msg % (deprecated_version_string, python_version_string())) + + if not options.help: + # [ ] Clarify why we need to create Builder here at all, and + # why it is created in DefaultEnvironment + # https://bitbucket.org/scons/scons/commits/d27a548aeee8ad5e67ea75c2d19a7d305f784e30 + if SCons.SConf.NeedConfigHBuilder(): + SCons.SConf.CreateConfigHBuilder(SCons.Defaults.DefaultEnvironment()) + + # Now re-parse the command-line options (any to the left of a '--' + # argument, that is) with any user-defined command-line options that + # the SConscript files may have added to the parser object. This will + # emit the appropriate error message and exit if any unknown option + # was specified on the command line. + + parser.preserve_unknown_options = False + parser.parse_args(parser.largs, options) + + if options.help: + help_text = SCons.Script.help_text + if help_text is None: + # They specified -h, but there was no Help() inside the + # SConscript files. Give them the options usage. + raise SConsPrintHelpException + else: + print(help_text) + print("Use scons -H for help about command-line options.") + exit_status = 0 + return + + # Change directory to the top-level SConstruct directory, then tell + # the Node.FS subsystem that we're all done reading the SConscript + # files and calling Repository() and VariantDir() and changing + # directories and the like, so it can go ahead and start memoizing + # the string values of file system nodes. + + fs.chdir(fs.Top) + + SCons.Node.FS.save_strings(1) + + # Now that we've read the SConscripts we can set the options + # that are SConscript settable: + SCons.Node.implicit_cache = options.implicit_cache + SCons.Node.FS.set_duplicate(options.duplicate) + fs.set_max_drift(options.max_drift) + + SCons.Job.explicit_stack_size = options.stack_size + + if options.md5_chunksize: + SCons.Node.FS.File.md5_chunksize = options.md5_chunksize + + platform = SCons.Platform.platform_module() + + if options.interactive: + SCons.Script.Interactive.interact(fs, OptionsParser, options, + targets, target_top) + + else: + + # Build the targets + nodes = _build_targets(fs, options, targets, target_top) + if not nodes: + revert_io() + print('Found nothing to build') + exit_status = 2 + +def _build_targets(fs, options, targets, target_top): + + global this_build_status + this_build_status = 0 + + progress_display.set_mode(not (options.no_progress or options.silent)) + display.set_mode(not options.silent) + SCons.Action.print_actions = not options.silent + SCons.Action.execute_actions = not options.no_exec + SCons.Node.do_store_info = not options.no_exec + SCons.SConf.dryrun = options.no_exec + + if options.diskcheck: + SCons.Node.FS.set_diskcheck(options.diskcheck) + + SCons.CacheDir.cache_enabled = not options.cache_disable + SCons.CacheDir.cache_readonly = options.cache_readonly + SCons.CacheDir.cache_debug = options.cache_debug + SCons.CacheDir.cache_force = options.cache_force + SCons.CacheDir.cache_show = options.cache_show + + if options.no_exec: + CleanTask.execute = CleanTask.show + else: + CleanTask.execute = CleanTask.remove + + lookup_top = None + if targets or SCons.Script.BUILD_TARGETS != SCons.Script._build_plus_default: + # They specified targets on the command line or modified + # BUILD_TARGETS in the SConscript file(s), so if they used -u, + # -U or -D, we have to look up targets relative to the top, + # but we build whatever they specified. + if target_top: + lookup_top = fs.Dir(target_top) + target_top = None + + targets = SCons.Script.BUILD_TARGETS + else: + # There are no targets specified on the command line, + # so if they used -u, -U or -D, we may have to restrict + # what actually gets built. + d = None + if target_top: + if options.climb_up == 1: + # -u, local directory and below + target_top = fs.Dir(target_top) + lookup_top = target_top + elif options.climb_up == 2: + # -D, all Default() targets + target_top = None + lookup_top = None + elif options.climb_up == 3: + # -U, local SConscript Default() targets + target_top = fs.Dir(target_top) + def check_dir(x, target_top=target_top): + if hasattr(x, 'cwd') and not x.cwd is None: + cwd = x.cwd.srcnode() + return cwd == target_top + else: + # x doesn't have a cwd, so it's either not a target, + # or not a file, so go ahead and keep it as a default + # target and let the engine sort it out: + return 1 + d = [tgt for tgt in SCons.Script.DEFAULT_TARGETS if check_dir(tgt)] + SCons.Script.DEFAULT_TARGETS[:] = d + target_top = None + lookup_top = None + + targets = SCons.Script._Get_Default_Targets(d, fs) + + if not targets: + sys.stderr.write("scons: *** No targets specified and no Default() targets found. Stop.\n") + return None + + def Entry(x, ltop=lookup_top, ttop=target_top, fs=fs): + if isinstance(x, SCons.Node.Node): + node = x + else: + node = None + # Why would ltop be None? Unfortunately this happens. + if ltop is None: ltop = '' + # Curdir becomes important when SCons is called with -u, -C, + # or similar option that changes directory, and so the paths + # of targets given on the command line need to be adjusted. + curdir = os.path.join(os.getcwd(), str(ltop)) + for lookup in SCons.Node.arg2nodes_lookups: + node = lookup(x, curdir=curdir) + if node is not None: + break + if node is None: + node = fs.Entry(x, directory=ltop, create=1) + if ttop and not node.is_under(ttop): + if isinstance(node, SCons.Node.FS.Dir) and ttop.is_under(node): + node = ttop + else: + node = None + return node + + nodes = [_f for _f in map(Entry, targets) if _f] + + task_class = BuildTask # default action is to build targets + opening_message = "Building targets ..." + closing_message = "done building targets." + if options.keep_going: + failure_message = "done building targets (errors occurred during build)." + else: + failure_message = "building terminated because of errors." + if options.question: + task_class = QuestionTask + try: + if options.clean: + task_class = CleanTask + opening_message = "Cleaning targets ..." + closing_message = "done cleaning targets." + if options.keep_going: + failure_message = "done cleaning targets (errors occurred during clean)." + else: + failure_message = "cleaning terminated because of errors." + except AttributeError: + pass + + task_class.progress = ProgressObject + + if options.random: + def order(dependencies): + """Randomize the dependencies.""" + import random + random.shuffle(dependencies) + return dependencies + else: + def order(dependencies): + """Leave the order of dependencies alone.""" + return dependencies + + if options.taskmastertrace_file == '-': + tmtrace = sys.stdout + elif options.taskmastertrace_file: + tmtrace = open(options.taskmastertrace_file, 'w') + else: + tmtrace = None + taskmaster = SCons.Taskmaster.Taskmaster(nodes, task_class, order, tmtrace) + + # Let the BuildTask objects get at the options to respond to the + # various print_* settings, tree_printer list, etc. + BuildTask.options = options + + + is_pypy = platform.python_implementation() == 'PyPy' + # As of 3.7, python removed support for threadless platforms. + # See https://www.python.org/dev/peps/pep-0011/ + is_37_or_later = sys.version_info >= (3, 7) + python_has_threads = sysconfig.get_config_var('WITH_THREAD') or is_pypy or is_37_or_later + # to check if python configured with threads. + global num_jobs + num_jobs = options.num_jobs + jobs = SCons.Job.Jobs(num_jobs, taskmaster) + if num_jobs > 1: + msg = None + if sys.platform == 'win32': + msg = fetch_win32_parallel_msg() + elif jobs.num_jobs == 1 or not python_has_threads: + msg = "parallel builds are unsupported by this version of Python;\n" + \ + "\tignoring -j or num_jobs option.\n" + if msg: + SCons.Warnings.warn(SCons.Warnings.NoParallelSupportWarning, msg) + + memory_stats.append('before building targets:') + count_stats.append(('pre-', 'build')) + + def jobs_postfunc( + jobs=jobs, + options=options, + closing_message=closing_message, + failure_message=failure_message + ): + if jobs.were_interrupted(): + if not options.no_progress and not options.silent: + sys.stderr.write("scons: Build interrupted.\n") + global exit_status + global this_build_status + exit_status = 2 + this_build_status = 2 + + if this_build_status: + progress_display("scons: " + failure_message) + else: + progress_display("scons: " + closing_message) + if not options.no_exec: + if jobs.were_interrupted(): + progress_display("scons: writing .sconsign file.") + SCons.SConsign.write() + + progress_display("scons: " + opening_message) + jobs.run(postfunc = jobs_postfunc) + + memory_stats.append('after building targets:') + count_stats.append(('post-', 'build')) + + return nodes + +def _exec_main(parser, values): + sconsflags = os.environ.get('SCONSFLAGS', '') + all_args = sconsflags.split() + sys.argv[1:] + + options, args = parser.parse_args(all_args, values) + + if isinstance(options.debug, list) and "pdb" in options.debug: + import pdb + pdb.Pdb().runcall(_main, parser) + elif options.profile_file: + # compat layer imports "cProfile" for us if it's available. + from profile import Profile + + prof = Profile() + try: + prof.runcall(_main, parser) + finally: + prof.dump_stats(options.profile_file) + else: + _main(parser) + +def main(): + global OptionsParser + global exit_status + global first_command_start + + # Check up front for a Python version we do not support. We + # delay the check for deprecated Python versions until later, + # after the SConscript files have been read, in case they + # disable that warning. + if python_version_unsupported(): + msg = "scons: *** SCons version %s does not run under Python version %s.\n" + sys.stderr.write(msg % (SCons.__version__, python_version_string())) + sys.exit(1) + + parts = ["SCons by Steven Knight et al.:\n"] + try: + import __main__ + parts.append(version_string("script", __main__)) + except (ImportError, AttributeError): + # On Windows there is no scons.py, so there is no + # __main__.__version__, hence there is no script version. + pass + parts.append(version_string("engine", SCons)) + parts.append(path_string("engine", SCons)) + parts.append("Copyright (c) 2001 - 2019 The SCons Foundation") + version = ''.join(parts) + + from . import SConsOptions + parser = SConsOptions.Parser(version) + values = SConsOptions.SConsValues(parser.get_default_values()) + + OptionsParser = parser + + try: + try: + _exec_main(parser, values) + finally: + revert_io() + except SystemExit as s: + if s: + exit_status = s.code + except KeyboardInterrupt: + print("scons: Build interrupted.") + sys.exit(2) + except SyntaxError as e: + _scons_syntax_error(e) + except SCons.Errors.InternalError: + _scons_internal_error() + except SCons.Errors.UserError as e: + _scons_user_error(e) + except SConsPrintHelpException: + parser.print_help() + exit_status = 0 + except SCons.Errors.BuildError as e: + print(e) + exit_status = e.exitstatus + except: + # An exception here is likely a builtin Python exception Python + # code in an SConscript file. Show them precisely what the + # problem was and where it happened. + SCons.Script._SConscript.SConscript_exception() + sys.exit(2) + + memory_stats.print_stats() + count_stats.print_stats() + + if print_objects: + SCons.Debug.listLoggedInstances('*') + #SCons.Debug.dumpLoggedInstances('*') + + if print_memoizer: + SCons.Memoize.Dump("Memoizer (memory cache) hits and misses:") + + # Dump any development debug info that may have been enabled. + # These are purely for internal debugging during development, so + # there's no need to control them with --debug= options; they're + # controlled by changing the source code. + SCons.Debug.dump_caller_counts() + SCons.Taskmaster.dump_stats() + + if print_time: + total_time = time.time() - SCons.Script.start_time + if num_jobs == 1: + ct = cumulative_command_time + else: + if last_command_end is None or first_command_start is None: + ct = 0.0 + else: + ct = last_command_end - first_command_start + scons_time = total_time - sconscript_time - ct + print("Total build time: %f seconds"%total_time) + print("Total SConscript file execution time: %f seconds"%sconscript_time) + print("Total SCons execution time: %f seconds"%scons_time) + print("Total command execution time: %f seconds"%ct) + + sys.exit(exit_status) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Script/SConsOptions.py b/tools/scons/scons-local-3.0.5/SCons/Script/SConsOptions.py new file mode 100755 index 0000000000..65e1868f5e --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Script/SConsOptions.py @@ -0,0 +1,1000 @@ +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Script/SConsOptions.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import optparse +import re +import sys +import textwrap + +no_hyphen_re = re.compile(r'(\s+|(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))') + +try: + from gettext import gettext +except ImportError: + def gettext(message): + return message +_ = gettext + +import SCons.Node.FS +import SCons.Platform.virtualenv +import SCons.Warnings + +OptionValueError = optparse.OptionValueError +SUPPRESS_HELP = optparse.SUPPRESS_HELP + +diskcheck_all = SCons.Node.FS.diskcheck_types() + +def diskcheck_convert(value): + if value is None: + return [] + if not SCons.Util.is_List(value): + value = value.split(',') + result = [] + for v in value: + v = v.lower() + if v == 'all': + result = diskcheck_all + elif v == 'none': + result = [] + elif v in diskcheck_all: + result.append(v) + else: + raise ValueError(v) + return result + + +class SConsValues(optparse.Values): + """ + Holder class for uniform access to SCons options, regardless + of whether or not they can be set on the command line or in the + SConscript files (using the SetOption() function). + + A SCons option value can originate three different ways: + + 1) set on the command line; + 2) set in an SConscript file; + 3) the default setting (from the the op.add_option() + calls in the Parser() function, below). + + The command line always overrides a value set in a SConscript file, + which in turn always overrides default settings. Because we want + to support user-specified options in the SConscript file itself, + though, we may not know about all of the options when the command + line is first parsed, so we can't make all the necessary precedence + decisions at the time the option is configured. + + The solution implemented in this class is to keep these different sets + of settings separate (command line, SConscript file, and default) + and to override the __getattr__() method to check them in turn. + This should allow the rest of the code to just fetch values as + attributes of an instance of this class, without having to worry + about where they came from. + + Note that not all command line options are settable from SConscript + files, and the ones that are must be explicitly added to the + "settable" list in this class, and optionally validated and coerced + in the set_option() method. + """ + + def __init__(self, defaults): + self.__dict__['__defaults__'] = defaults + self.__dict__['__SConscript_settings__'] = {} + + def __getattr__(self, attr): + """ + Fetches an options value, checking first for explicit settings + from the command line (which are direct attributes), then the + SConscript file settings, then the default values. + """ + try: + return self.__dict__[attr] + except KeyError: + try: + return self.__dict__['__SConscript_settings__'][attr] + except KeyError: + try: + return getattr(self.__dict__['__defaults__'], attr) + except KeyError: + # Added because with py3 this is a new class, + # not a classic class, and due to the way + # In that case it will create an object without + # __defaults__, and then query for __setstate__ + # which will throw an exception of KeyError + # deepcopy() is expecting AttributeError if __setstate__ + # is not available. + raise AttributeError(attr) + + + settable = [ + 'clean', + 'diskcheck', + 'duplicate', + 'help', + 'implicit_cache', + 'max_drift', + 'md5_chunksize', + 'no_exec', + 'num_jobs', + 'random', + 'stack_size', + 'warn', + 'silent' + ] + + def set_option(self, name, value): + """ + Sets an option from an SConscript file. + """ + if not name in self.settable: + raise SCons.Errors.UserError("This option is not settable from a SConscript file: %s"%name) + + if name == 'num_jobs': + try: + value = int(value) + if value < 1: + raise ValueError + except ValueError: + raise SCons.Errors.UserError("A positive integer is required: %s"%repr(value)) + elif name == 'max_drift': + try: + value = int(value) + except ValueError: + raise SCons.Errors.UserError("An integer is required: %s"%repr(value)) + elif name == 'duplicate': + try: + value = str(value) + except ValueError: + raise SCons.Errors.UserError("A string is required: %s"%repr(value)) + if not value in SCons.Node.FS.Valid_Duplicates: + raise SCons.Errors.UserError("Not a valid duplication style: %s" % value) + # Set the duplicate style right away so it can affect linking + # of SConscript files. + SCons.Node.FS.set_duplicate(value) + elif name == 'diskcheck': + try: + value = diskcheck_convert(value) + except ValueError as v: + raise SCons.Errors.UserError("Not a valid diskcheck value: %s"%v) + if 'diskcheck' not in self.__dict__: + # No --diskcheck= option was specified on the command line. + # Set this right away so it can affect the rest of the + # file/Node lookups while processing the SConscript files. + SCons.Node.FS.set_diskcheck(value) + elif name == 'stack_size': + try: + value = int(value) + except ValueError: + raise SCons.Errors.UserError("An integer is required: %s"%repr(value)) + elif name == 'md5_chunksize': + try: + value = int(value) + except ValueError: + raise SCons.Errors.UserError("An integer is required: %s"%repr(value)) + elif name == 'warn': + if SCons.Util.is_String(value): + value = [value] + value = self.__SConscript_settings__.get(name, []) + value + SCons.Warnings.process_warn_strings(value) + + self.__SConscript_settings__[name] = value + + +class SConsOption(optparse.Option): + def convert_value(self, opt, value): + if value is not None: + if self.nargs in (1, '?'): + return self.check_value(opt, value) + else: + return tuple([self.check_value(opt, v) for v in value]) + + def process(self, opt, value, values, parser): + + # First, convert the value(s) to the right type. Howl if any + # value(s) are bogus. + value = self.convert_value(opt, value) + + # And then take whatever action is expected of us. + # This is a separate method to make life easier for + # subclasses to add new actions. + return self.take_action( + self.action, self.dest, opt, value, values, parser) + + def _check_nargs_optional(self): + if self.nargs == '?' and self._short_opts: + fmt = "option %s: nargs='?' is incompatible with short options" + raise SCons.Errors.UserError(fmt % self._short_opts[0]) + + try: + _orig_CONST_ACTIONS = optparse.Option.CONST_ACTIONS + + _orig_CHECK_METHODS = optparse.Option.CHECK_METHODS + + except AttributeError: + # optparse.Option had no CONST_ACTIONS before Python 2.5. + + _orig_CONST_ACTIONS = ("store_const",) + + def _check_const(self): + if self.action not in self.CONST_ACTIONS and self.const is not None: + raise OptionError( + "'const' must not be supplied for action %r" % self.action, + self) + + # optparse.Option collects its list of unbound check functions + # up front. This sucks because it means we can't just override + # the _check_const() function like a normal method, we have to + # actually replace it in the list. This seems to be the most + # straightforward way to do that. + + _orig_CHECK_METHODS = [optparse.Option._check_action, + optparse.Option._check_type, + optparse.Option._check_choice, + optparse.Option._check_dest, + _check_const, + optparse.Option._check_nargs, + optparse.Option._check_callback] + + CHECK_METHODS = _orig_CHECK_METHODS + [_check_nargs_optional] + + CONST_ACTIONS = _orig_CONST_ACTIONS + optparse.Option.TYPED_ACTIONS + +class SConsOptionGroup(optparse.OptionGroup): + """ + A subclass for SCons-specific option groups. + + The only difference between this and the base class is that we print + the group's help text flush left, underneath their own title but + lined up with the normal "SCons Options". + """ + def format_help(self, formatter): + """ + Format an option group's help text, outdenting the title so it's + flush with the "SCons Options" title we print at the top. + """ + formatter.dedent() + result = formatter.format_heading(self.title) + formatter.indent() + result = result + optparse.OptionContainer.format_help(self, formatter) + return result + +class SConsOptionParser(optparse.OptionParser): + preserve_unknown_options = False + + def error(self, msg): + # overridden OptionValueError exception handler + self.print_usage(sys.stderr) + sys.stderr.write("SCons Error: %s\n" % msg) + sys.exit(2) + + def _process_long_opt(self, rargs, values): + """ + SCons-specific processing of long options. + + This is copied directly from the normal + optparse._process_long_opt() method, except that, if configured + to do so, we catch the exception thrown when an unknown option + is encountered and just stick it back on the "leftover" arguments + for later (re-)processing. + """ + arg = rargs.pop(0) + + # Value explicitly attached to arg? Pretend it's the next + # argument. + if "=" in arg: + (opt, next_arg) = arg.split("=", 1) + rargs.insert(0, next_arg) + had_explicit_value = True + else: + opt = arg + had_explicit_value = False + + try: + opt = self._match_long_opt(opt) + except optparse.BadOptionError: + if self.preserve_unknown_options: + # SCons-specific: if requested, add unknown options to + # the "leftover arguments" list for later processing. + self.largs.append(arg) + if had_explicit_value: + # The unknown option will be re-processed later, + # so undo the insertion of the explicit value. + rargs.pop(0) + return + raise + + option = self._long_opt[opt] + if option.takes_value(): + nargs = option.nargs + if nargs == '?': + if had_explicit_value: + value = rargs.pop(0) + else: + value = option.const + elif len(rargs) < nargs: + if nargs == 1: + if not option.choices: + self.error(_("%s option requires an argument") % opt) + else: + msg = _("%s option requires an argument " % opt) + msg += _("(choose from %s)" + % ', '.join(option.choices)) + self.error(msg) + else: + self.error(_("%s option requires %d arguments") + % (opt, nargs)) + elif nargs == 1: + value = rargs.pop(0) + else: + value = tuple(rargs[0:nargs]) + del rargs[0:nargs] + + elif had_explicit_value: + self.error(_("%s option does not take a value") % opt) + + else: + value = None + + option.process(opt, value, values, self) + + def reparse_local_options(self): + """ + Re-parse the leftover command-line options stored + in self.largs, so that any value overridden on the + command line is immediately available if the user turns + around and does a GetOption() right away. + + We mimic the processing of the single args + in the original OptionParser._process_args(), but here we + allow exact matches for long-opts only (no partial + argument names!). + + Else, this would lead to problems in add_local_option() + below. When called from there, we try to reparse the + command-line arguments that + 1. haven't been processed so far (self.largs), but + 2. are possibly not added to the list of options yet. + + So, when we only have a value for "--myargument" yet, + a command-line argument of "--myarg=test" would set it. + Responsible for this behaviour is the method + _match_long_opt(), which allows for partial matches of + the option name, as long as the common prefix appears to + be unique. + This would lead to further confusion, because we might want + to add another option "--myarg" later on (see issue #2929). + + """ + rargs = [] + largs_restore = [] + # Loop over all remaining arguments + skip = False + for l in self.largs: + if skip: + # Accept all remaining arguments as they are + largs_restore.append(l) + else: + if len(l) > 2 and l[0:2] == "--": + # Check long option + lopt = (l,) + if "=" in l: + # Split into option and value + lopt = l.split("=", 1) + + if lopt[0] in self._long_opt: + # Argument is already known + rargs.append('='.join(lopt)) + else: + # Not known yet, so reject for now + largs_restore.append('='.join(lopt)) + else: + if l == "--" or l == "-": + # Stop normal processing and don't + # process the rest of the command-line opts + largs_restore.append(l) + skip = True + else: + rargs.append(l) + + # Parse the filtered list + self.parse_args(rargs, self.values) + # Restore the list of remaining arguments for the + # next call of AddOption/add_local_option... + self.largs = self.largs + largs_restore + + def add_local_option(self, *args, **kw): + """ + Adds a local option to the parser. + + This is initiated by a SetOption() call to add a user-defined + command-line option. We add the option to a separate option + group for the local options, creating the group if necessary. + """ + try: + group = self.local_option_group + except AttributeError: + group = SConsOptionGroup(self, 'Local Options') + group = self.add_option_group(group) + self.local_option_group = group + + result = group.add_option(*args, **kw) + + if result: + # The option was added successfully. We now have to add the + # default value to our object that holds the default values + # (so that an attempt to fetch the option's attribute will + # yield the default value when not overridden) and then + # we re-parse the leftover command-line options, so that + # any value overridden on the command line is immediately + # available if the user turns around and does a GetOption() + # right away. + setattr(self.values.__defaults__, result.dest, result.default) + self.reparse_local_options() + + return result + +class SConsIndentedHelpFormatter(optparse.IndentedHelpFormatter): + def format_usage(self, usage): + return "usage: %s\n" % usage + + def format_heading(self, heading): + """ + This translates any heading of "options" or "Options" into + "SCons Options." Unfortunately, we have to do this here, + because those titles are hard-coded in the optparse calls. + """ + if heading == 'Options': + heading = "SCons Options" + return optparse.IndentedHelpFormatter.format_heading(self, heading) + + def format_option(self, option): + """ + A copy of the normal optparse.IndentedHelpFormatter.format_option() + method. This has been snarfed so we can modify text wrapping to + out liking: + + -- add our own regular expression that doesn't break on hyphens + (so things like --no-print-directory don't get broken); + + -- wrap the list of options themselves when it's too long + (the wrapper.fill(opts) call below); + + -- set the subsequent_indent when wrapping the help_text. + """ + # The help for each option consists of two parts: + # * the opt strings and metavars + # eg. ("-x", or "-fFILENAME, --file=FILENAME") + # * the user-supplied help string + # eg. ("turn on expert mode", "read data from FILENAME") + # + # If possible, we write both of these on the same line: + # -x turn on expert mode + # + # But if the opt string list is too long, we put the help + # string on a second line, indented to the same column it would + # start in if it fit on the first line. + # -fFILENAME, --file=FILENAME + # read data from FILENAME + result = [] + + opts = self.option_strings[option] + opt_width = self.help_position - self.current_indent - 2 + if len(opts) > opt_width: + wrapper = textwrap.TextWrapper(width=self.width, + initial_indent = ' ', + subsequent_indent = ' ') + wrapper.wordsep_re = no_hyphen_re + opts = wrapper.fill(opts) + '\n' + indent_first = self.help_position + else: # start help on same line as opts + opts = "%*s%-*s " % (self.current_indent, "", opt_width, opts) + indent_first = 0 + result.append(opts) + if option.help: + + help_text = self.expand_default(option) + + # SCons: indent every line of the help text but the first. + wrapper = textwrap.TextWrapper(width=self.help_width, + subsequent_indent = ' ') + wrapper.wordsep_re = no_hyphen_re + help_lines = wrapper.wrap(help_text) + result.append("%*s%s\n" % (indent_first, "", help_lines[0])) + for line in help_lines[1:]: + result.append("%*s%s\n" % (self.help_position, "", line)) + elif opts[-1] != "\n": + result.append("\n") + return "".join(result) + +def Parser(version): + """ + Returns an options parser object initialized with the standard + SCons options. + """ + + formatter = SConsIndentedHelpFormatter(max_help_position=30) + + op = SConsOptionParser(option_class=SConsOption, + add_help_option=False, + formatter=formatter, + usage="usage: scons [OPTION] [TARGET] ...",) + + op.preserve_unknown_options = True + op.version = version + + # Add the options to the parser we just created. + # + # These are in the order we want them to show up in the -H help + # text, basically alphabetical. Each op.add_option() call below + # should have a consistent format: + # + # op.add_option("-L", "--long-option-name", + # nargs=1, type="string", + # dest="long_option_name", default='foo', + # action="callback", callback=opt_long_option, + # help="help text goes here", + # metavar="VAR") + # + # Even though the optparse module constructs reasonable default + # destination names from the long option names, we're going to be + # explicit about each one for easier readability and so this code + # will at least show up when grepping the source for option attribute + # names, or otherwise browsing the source code. + + # options ignored for compatibility + def opt_ignore(option, opt, value, parser): + sys.stderr.write("Warning: ignoring %s option\n" % opt) + op.add_option("-b", "-d", "-e", "-m", "-S", "-t", "-w", + "--environment-overrides", + "--no-keep-going", + "--no-print-directory", + "--print-directory", + "--stop", + "--touch", + action="callback", callback=opt_ignore, + help="Ignored for compatibility.") + + op.add_option('-c', '--clean', '--remove', + dest="clean", default=False, + action="store_true", + help="Remove specified targets and dependencies.") + + op.add_option('-C', '--directory', + nargs=1, type="string", + dest="directory", default=[], + action="append", + help="Change to DIR before doing anything.", + metavar="DIR") + + op.add_option('--cache-debug', + nargs=1, + dest="cache_debug", default=None, + action="store", + help="Print CacheDir debug info to FILE.", + metavar="FILE") + + op.add_option('--cache-disable', '--no-cache', + dest='cache_disable', default=False, + action="store_true", + help="Do not retrieve built targets from CacheDir.") + + op.add_option('--cache-force', '--cache-populate', + dest='cache_force', default=False, + action="store_true", + help="Copy already-built targets into the CacheDir.") + + op.add_option('--cache-readonly', + dest='cache_readonly', default=False, + action="store_true", + help="Do not update CacheDir with built targets.") + + op.add_option('--cache-show', + dest='cache_show', default=False, + action="store_true", + help="Print build actions for files from CacheDir.") + + def opt_invalid(group, value, options): + errmsg = "`%s' is not a valid %s option type, try:\n" % (value, group) + return errmsg + " %s" % ", ".join(options) + + config_options = ["auto", "force" ,"cache"] + + opt_config_help = "Controls Configure subsystem: %s." \ + % ", ".join(config_options) + + op.add_option('--config', + nargs=1, choices=config_options, + dest="config", default="auto", + help = opt_config_help, + metavar="MODE") + + op.add_option('-D', + dest="climb_up", default=None, + action="store_const", const=2, + help="Search up directory tree for SConstruct, " + "build all Default() targets.") + + deprecated_debug_options = { + "dtree" : '; please use --tree=derived instead', + "nomemoizer" : ' and has no effect', + "stree" : '; please use --tree=all,status instead', + "tree" : '; please use --tree=all instead', + } + + debug_options = ["count", "duplicate", "explain", "findlibs", + "includes", "memoizer", "memory", "objects", + "pdb", "prepare", "presub", "stacktrace", + "time"] + + def opt_debug(option, opt, value__, parser, + debug_options=debug_options, + deprecated_debug_options=deprecated_debug_options): + for value in value__.split(','): + if value in debug_options: + parser.values.debug.append(value) + elif value in list(deprecated_debug_options.keys()): + parser.values.debug.append(value) + try: + parser.values.delayed_warnings + except AttributeError: + parser.values.delayed_warnings = [] + msg = deprecated_debug_options[value] + w = "The --debug=%s option is deprecated%s." % (value, msg) + t = (SCons.Warnings.DeprecatedDebugOptionsWarning, w) + parser.values.delayed_warnings.append(t) + else: + raise OptionValueError(opt_invalid('debug', value, debug_options)) + + opt_debug_help = "Print various types of debugging information: %s." \ + % ", ".join(debug_options) + op.add_option('--debug', + nargs=1, type="string", + dest="debug", default=[], + action="callback", callback=opt_debug, + help=opt_debug_help, + metavar="TYPE") + + def opt_diskcheck(option, opt, value, parser): + try: + diskcheck_value = diskcheck_convert(value) + except ValueError as e: + raise OptionValueError("`%s' is not a valid diskcheck type" % e) + setattr(parser.values, option.dest, diskcheck_value) + + op.add_option('--diskcheck', + nargs=1, type="string", + dest='diskcheck', default=None, + action="callback", callback=opt_diskcheck, + help="Enable specific on-disk checks.", + metavar="TYPE") + + def opt_duplicate(option, opt, value, parser): + if not value in SCons.Node.FS.Valid_Duplicates: + raise OptionValueError(opt_invalid('duplication', value, + SCons.Node.FS.Valid_Duplicates)) + setattr(parser.values, option.dest, value) + # Set the duplicate style right away so it can affect linking + # of SConscript files. + SCons.Node.FS.set_duplicate(value) + + opt_duplicate_help = "Set the preferred duplication methods. Must be one of " \ + + ", ".join(SCons.Node.FS.Valid_Duplicates) + + op.add_option('--duplicate', + nargs=1, type="string", + dest="duplicate", default='hard-soft-copy', + action="callback", callback=opt_duplicate, + help=opt_duplicate_help) + + if not SCons.Platform.virtualenv.virtualenv_enabled_by_default: + op.add_option('--enable-virtualenv', + dest="enable_virtualenv", + action="store_true", + help="Import certain virtualenv variables to SCons") + + op.add_option('-f', '--file', '--makefile', '--sconstruct', + nargs=1, type="string", + dest="file", default=[], + action="append", + help="Read FILE as the top-level SConstruct file.") + + op.add_option('-h', '--help', + dest="help", default=False, + action="store_true", + help="Print defined help message, or this one.") + + op.add_option("-H", "--help-options", + action="help", + help="Print this message and exit.") + + op.add_option('-i', '--ignore-errors', + dest='ignore_errors', default=False, + action="store_true", + help="Ignore errors from build actions.") + + op.add_option('-I', '--include-dir', + nargs=1, + dest='include_dir', default=[], + action="append", + help="Search DIR for imported Python modules.", + metavar="DIR") + + op.add_option('--ignore-virtualenv', + dest="ignore_virtualenv", + action="store_true", + help="Do not import virtualenv variables to SCons") + + op.add_option('--implicit-cache', + dest='implicit_cache', default=False, + action="store_true", + help="Cache implicit dependencies") + + def opt_implicit_deps(option, opt, value, parser): + setattr(parser.values, 'implicit_cache', True) + setattr(parser.values, option.dest, True) + + op.add_option('--implicit-deps-changed', + dest="implicit_deps_changed", default=False, + action="callback", callback=opt_implicit_deps, + help="Ignore cached implicit dependencies.") + + op.add_option('--implicit-deps-unchanged', + dest="implicit_deps_unchanged", default=False, + action="callback", callback=opt_implicit_deps, + help="Ignore changes in implicit dependencies.") + + op.add_option('--interact', '--interactive', + dest='interactive', default=False, + action="store_true", + help="Run in interactive mode.") + + op.add_option('-j', '--jobs', + nargs=1, type="int", + dest="num_jobs", default=1, + action="store", + help="Allow N jobs at once.", + metavar="N") + + op.add_option('-k', '--keep-going', + dest='keep_going', default=False, + action="store_true", + help="Keep going when a target can't be made.") + + op.add_option('--max-drift', + nargs=1, type="int", + dest='max_drift', default=SCons.Node.FS.default_max_drift, + action="store", + help="Set maximum system clock drift to N seconds.", + metavar="N") + + op.add_option('--md5-chunksize', + nargs=1, type="int", + dest='md5_chunksize', default=SCons.Node.FS.File.md5_chunksize, + action="store", + help="Set chunk-size for MD5 signature computation to N kilobytes.", + metavar="N") + + op.add_option('-n', '--no-exec', '--just-print', '--dry-run', '--recon', + dest='no_exec', default=False, + action="store_true", + help="Don't build; just print commands.") + + op.add_option('--no-site-dir', + dest='no_site_dir', default=False, + action="store_true", + help="Don't search or use the usual site_scons dir.") + + op.add_option('--profile', + nargs=1, + dest="profile_file", default=None, + action="store", + help="Profile SCons and put results in FILE.", + metavar="FILE") + + op.add_option('-q', '--question', + dest="question", default=False, + action="store_true", + help="Don't build; exit status says if up to date.") + + op.add_option('-Q', + dest='no_progress', default=False, + action="store_true", + help="Suppress \"Reading/Building\" progress messages.") + + op.add_option('--random', + dest="random", default=False, + action="store_true", + help="Build dependencies in random order.") + + op.add_option('-s', '--silent', '--quiet', + dest="silent", default=False, + action="store_true", + help="Don't print commands.") + + op.add_option('--site-dir', + nargs=1, + dest='site_dir', default=None, + action="store", + help="Use DIR instead of the usual site_scons dir.", + metavar="DIR") + + op.add_option('--stack-size', + nargs=1, type="int", + dest='stack_size', + action="store", + help="Set the stack size of the threads used to run jobs to N kilobytes.", + metavar="N") + + op.add_option('--taskmastertrace', + nargs=1, + dest="taskmastertrace_file", default=None, + action="store", + help="Trace Node evaluation to FILE.", + metavar="FILE") + + tree_options = ["all", "derived", "prune", "status"] + + def opt_tree(option, opt, value, parser, tree_options=tree_options): + from . import Main + tp = Main.TreePrinter() + for o in value.split(','): + if o == 'all': + tp.derived = False + elif o == 'derived': + tp.derived = True + elif o == 'prune': + tp.prune = True + elif o == 'status': + tp.status = True + else: + raise OptionValueError(opt_invalid('--tree', o, tree_options)) + parser.values.tree_printers.append(tp) + + opt_tree_help = "Print a dependency tree in various formats: %s." \ + % ", ".join(tree_options) + + op.add_option('--tree', + nargs=1, type="string", + dest="tree_printers", default=[], + action="callback", callback=opt_tree, + help=opt_tree_help, + metavar="OPTIONS") + + op.add_option('-u', '--up', '--search-up', + dest="climb_up", default=0, + action="store_const", const=1, + help="Search up directory tree for SConstruct, " + "build targets at or below current directory.") + + op.add_option('-U', + dest="climb_up", default=0, + action="store_const", const=3, + help="Search up directory tree for SConstruct, " + "build Default() targets from local SConscript.") + + def opt_version(option, opt, value, parser): + sys.stdout.write(parser.version + '\n') + sys.exit(0) + op.add_option("-v", "--version", + action="callback", callback=opt_version, + help="Print the SCons version number and exit.") + + def opt_warn(option, opt, value, parser, tree_options=tree_options): + if SCons.Util.is_String(value): + value = value.split(',') + parser.values.warn.extend(value) + + op.add_option('--warn', '--warning', + nargs=1, type="string", + dest="warn", default=[], + action="callback", callback=opt_warn, + help="Enable or disable warnings.", + metavar="WARNING-SPEC") + + op.add_option('-Y', '--repository', '--srcdir', + nargs=1, + dest="repository", default=[], + action="append", + help="Search REPOSITORY for source and target files.") + + + # Options from Make and Cons classic that we do not yet support, + # but which we may support someday and whose (potential) meanings + # we don't want to change. These all get a "the -X option is not + # yet implemented" message and don't show up in the help output. + + def opt_not_yet(option, opt, value, parser): + msg = "Warning: the %s option is not yet implemented\n" % opt + sys.stderr.write(msg) + + op.add_option('-l', '--load-average', '--max-load', + nargs=1, type="float", + dest="load_average", default=0, + action="callback", callback=opt_not_yet, + # action="store", + # help="Don't start multiple jobs unless load is below " + # "LOAD-AVERAGE." + help=SUPPRESS_HELP) + op.add_option('--list-actions', + dest="list_actions", + action="callback", callback=opt_not_yet, + # help="Don't build; list files and build actions." + help=SUPPRESS_HELP) + op.add_option('--list-derived', + dest="list_derived", + action="callback", callback=opt_not_yet, + # help="Don't build; list files that would be built." + help=SUPPRESS_HELP) + op.add_option('--list-where', + dest="list_where", + action="callback", callback=opt_not_yet, + # help="Don't build; list files and where defined." + help=SUPPRESS_HELP) + op.add_option('-o', '--old-file', '--assume-old', + nargs=1, type="string", + dest="old_file", default=[], + action="callback", callback=opt_not_yet, + # action="append", + # help = "Consider FILE to be old; don't rebuild it." + help=SUPPRESS_HELP) + op.add_option('--override', + nargs=1, type="string", + action="callback", callback=opt_not_yet, + dest="override", + # help="Override variables as specified in FILE." + help=SUPPRESS_HELP) + op.add_option('-p', + action="callback", callback=opt_not_yet, + dest="p", + # help="Print internal environments/objects." + help=SUPPRESS_HELP) + op.add_option('-r', '-R', '--no-builtin-rules', '--no-builtin-variables', + action="callback", callback=opt_not_yet, + dest="no_builtin_rules", + # help="Clear default environments and variables." + help=SUPPRESS_HELP) + op.add_option('--write-filenames', + nargs=1, type="string", + dest="write_filenames", + action="callback", callback=opt_not_yet, + # help="Write all filenames examined into FILE." + help=SUPPRESS_HELP) + op.add_option('-W', '--new-file', '--assume-new', '--what-if', + nargs=1, type="string", + dest="new_file", + action="callback", callback=opt_not_yet, + # help="Consider FILE to be changed." + help=SUPPRESS_HELP) + op.add_option('--warn-undefined-variables', + dest="warn_undefined_variables", + action="callback", callback=opt_not_yet, + # help="Warn when an undefined variable is referenced." + help=SUPPRESS_HELP) + return op + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Script/SConscript.py b/tools/scons/scons-local-3.0.5/SCons/Script/SConscript.py new file mode 100755 index 0000000000..8377a54de4 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Script/SConscript.py @@ -0,0 +1,694 @@ +"""SCons.Script.SConscript + +This module defines the Python API provided to SConscript and SConstruct +files. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +__revision__ = "src/engine/SCons/Script/SConscript.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons +import SCons.Action +import SCons.Builder +import SCons.Defaults +import SCons.Environment +import SCons.Errors +import SCons.Node +import SCons.Node.Alias +import SCons.Node.FS +import SCons.Platform +import SCons.SConf +import SCons.Script.Main +import SCons.Tool +import SCons.Util + +from . import Main + +import collections +import os +import os.path +import re +import sys +import traceback +import time + +class SConscriptReturn(Exception): + pass + +launch_dir = os.path.abspath(os.curdir) + +GlobalDict = None + +# global exports set by Export(): +global_exports = {} + +# chdir flag +sconscript_chdir = 1 + +def get_calling_namespaces(): + """Return the locals and globals for the function that called + into this module in the current call stack.""" + try: 1//0 + except ZeroDivisionError: + # Don't start iterating with the current stack-frame to + # prevent creating reference cycles (f_back is safe). + frame = sys.exc_info()[2].tb_frame.f_back + + # Find the first frame that *isn't* from this file. This means + # that we expect all of the SCons frames that implement an Export() + # or SConscript() call to be in this file, so that we can identify + # the first non-Script.SConscript frame as the user's local calling + # environment, and the locals and globals dictionaries from that + # frame as the calling namespaces. See the comment below preceding + # the DefaultEnvironmentCall block for even more explanation. + while frame.f_globals.get("__name__") == __name__: + frame = frame.f_back + + return frame.f_locals, frame.f_globals + + +def compute_exports(exports): + """Compute a dictionary of exports given one of the parameters + to the Export() function or the exports argument to SConscript().""" + + loc, glob = get_calling_namespaces() + + retval = {} + try: + for export in exports: + if SCons.Util.is_Dict(export): + retval.update(export) + else: + try: + retval[export] = loc[export] + except KeyError: + retval[export] = glob[export] + except KeyError as x: + raise SCons.Errors.UserError("Export of non-existent variable '%s'"%x) + + return retval + +class Frame(object): + """A frame on the SConstruct/SConscript call stack""" + def __init__(self, fs, exports, sconscript): + self.globals = BuildDefaultGlobals() + self.retval = None + self.prev_dir = fs.getcwd() + self.exports = compute_exports(exports) # exports from the calling SConscript + # make sure the sconscript attr is a Node. + if isinstance(sconscript, SCons.Node.Node): + self.sconscript = sconscript + elif sconscript == '-': + self.sconscript = None + else: + self.sconscript = fs.File(str(sconscript)) + +# the SConstruct/SConscript call stack: +call_stack = [] + +# For documentation on the methods in this file, see the scons man-page + +def Return(*vars, **kw): + retval = [] + try: + fvars = SCons.Util.flatten(vars) + for var in fvars: + for v in var.split(): + retval.append(call_stack[-1].globals[v]) + except KeyError as x: + raise SCons.Errors.UserError("Return of non-existent variable '%s'"%x) + + if len(retval) == 1: + call_stack[-1].retval = retval[0] + else: + call_stack[-1].retval = tuple(retval) + + stop = kw.get('stop', True) + + if stop: + raise SConscriptReturn + + +stack_bottom = '% Stack boTTom %' # hard to define a variable w/this name :) + +def handle_missing_SConscript(f, must_exist=None): + """Take appropriate action on missing file in SConscript() call. + + Print a warning or raise an exception on missing file. + On first warning, print a deprecation message. + + Args: + f (str): path of missing configuration file + must_exist (bool): raise exception if file does not exist + + Raises: + UserError if 'must_exist' is True or if global + SCons.Script._no_missing_sconscript is True. + """ + + if must_exist or (SCons.Script._no_missing_sconscript and must_exist is not False): + msg = "Fatal: missing SConscript '%s'" % f.get_internal_path() + raise SCons.Errors.UserError(msg) + + if SCons.Script._warn_missing_sconscript_deprecated: + msg = "Calling missing SConscript without error is deprecated.\n" + \ + "Transition by adding must_exist=0 to SConscript calls.\n" + \ + "Missing SConscript '%s'" % f.get_internal_path() + SCons.Warnings.warn(SCons.Warnings.MissingSConscriptWarning, msg) + SCons.Script._warn_missing_sconscript_deprecated = False + else: + msg = "Ignoring missing SConscript '%s'" % f.get_internal_path() + SCons.Warnings.warn(SCons.Warnings.MissingSConscriptWarning, msg) + +def _SConscript(fs, *files, **kw): + top = fs.Top + sd = fs.SConstruct_dir.rdir() + exports = kw.get('exports', []) + + # evaluate each SConscript file + results = [] + for fn in files: + call_stack.append(Frame(fs, exports, fn)) + old_sys_path = sys.path + try: + SCons.Script.sconscript_reading = SCons.Script.sconscript_reading + 1 + if fn == "-": + exec(sys.stdin.read(), call_stack[-1].globals) + else: + if isinstance(fn, SCons.Node.Node): + f = fn + else: + f = fs.File(str(fn)) + _file_ = None + + # Change directory to the top of the source + # tree to make sure the os's cwd and the cwd of + # fs match so we can open the SConscript. + fs.chdir(top, change_os_dir=1) + if f.rexists(): + actual = f.rfile() + _file_ = open(actual.get_abspath(), "rb") + elif f.srcnode().rexists(): + actual = f.srcnode().rfile() + _file_ = open(actual.get_abspath(), "rb") + elif f.has_src_builder(): + # The SConscript file apparently exists in a source + # code management system. Build it, but then clear + # the builder so that it doesn't get built *again* + # during the actual build phase. + f.build() + f.built() + f.builder_set(None) + if f.exists(): + _file_ = open(f.get_abspath(), "rb") + if _file_: + # Chdir to the SConscript directory. Use a path + # name relative to the SConstruct file so that if + # we're using the -f option, we're essentially + # creating a parallel SConscript directory structure + # in our local directory tree. + # + # XXX This is broken for multiple-repository cases + # where the SConstruct and SConscript files might be + # in different Repositories. For now, cross that + # bridge when someone comes to it. + try: + src_dir = kw['src_dir'] + except KeyError: + ldir = fs.Dir(f.dir.get_path(sd)) + else: + ldir = fs.Dir(src_dir) + if not ldir.is_under(f.dir): + # They specified a source directory, but + # it's above the SConscript directory. + # Do the sensible thing and just use the + # SConcript directory. + ldir = fs.Dir(f.dir.get_path(sd)) + try: + fs.chdir(ldir, change_os_dir=sconscript_chdir) + except OSError: + # There was no local directory, so we should be + # able to chdir to the Repository directory. + # Note that we do this directly, not through + # fs.chdir(), because we still need to + # interpret the stuff within the SConscript file + # relative to where we are logically. + fs.chdir(ldir, change_os_dir=0) + os.chdir(actual.dir.get_abspath()) + + # Append the SConscript directory to the beginning + # of sys.path so Python modules in the SConscript + # directory can be easily imported. + sys.path = [ f.dir.get_abspath() ] + sys.path + + # This is the magic line that actually reads up + # and executes the stuff in the SConscript file. + # The locals for this frame contain the special + # bottom-of-the-stack marker so that any + # exceptions that occur when processing this + # SConscript can base the printed frames at this + # level and not show SCons internals as well. + call_stack[-1].globals.update({stack_bottom:1}) + old_file = call_stack[-1].globals.get('__file__') + try: + del call_stack[-1].globals['__file__'] + except KeyError: + pass + try: + try: + if Main.print_time: + time1 = time.time() + scriptdata = _file_.read() + scriptname = _file_.name + _file_.close() + exec(compile(scriptdata, scriptname, 'exec'), call_stack[-1].globals) + except SConscriptReturn: + pass + finally: + if Main.print_time: + time2 = time.time() + print('SConscript:%s took %0.3f ms' % (f.get_abspath(), (time2 - time1) * 1000.0)) + + if old_file is not None: + call_stack[-1].globals.update({__file__:old_file}) + else: + handle_missing_SConscript(f, kw.get('must_exist', None)) + + finally: + SCons.Script.sconscript_reading = SCons.Script.sconscript_reading - 1 + sys.path = old_sys_path + frame = call_stack.pop() + try: + fs.chdir(frame.prev_dir, change_os_dir=sconscript_chdir) + except OSError: + # There was no local directory, so chdir to the + # Repository directory. Like above, we do this + # directly. + fs.chdir(frame.prev_dir, change_os_dir=0) + rdir = frame.prev_dir.rdir() + rdir._create() # Make sure there's a directory there. + try: + os.chdir(rdir.get_abspath()) + except OSError as e: + # We still couldn't chdir there, so raise the error, + # but only if actions are being executed. + # + # If the -n option was used, the directory would *not* + # have been created and we should just carry on and + # let things muddle through. This isn't guaranteed + # to work if the SConscript files are reading things + # from disk (for example), but it should work well + # enough for most configurations. + if SCons.Action.execute_actions: + raise e + + results.append(frame.retval) + + # if we only have one script, don't return a tuple + if len(results) == 1: + return results[0] + else: + return tuple(results) + +def SConscript_exception(file=sys.stderr): + """Print an exception stack trace just for the SConscript file(s). + This will show users who have Python errors where the problem is, + without cluttering the output with all of the internal calls leading + up to where we exec the SConscript.""" + exc_type, exc_value, exc_tb = sys.exc_info() + tb = exc_tb + while tb and stack_bottom not in tb.tb_frame.f_locals: + tb = tb.tb_next + if not tb: + # We did not find our exec statement, so this was actually a bug + # in SCons itself. Show the whole stack. + tb = exc_tb + stack = traceback.extract_tb(tb) + try: + type = exc_type.__name__ + except AttributeError: + type = str(exc_type) + if type[:11] == "exceptions.": + type = type[11:] + file.write('%s: %s:\n' % (type, exc_value)) + for fname, line, func, text in stack: + file.write(' File "%s", line %d:\n' % (fname, line)) + file.write(' %s\n' % text) + +def annotate(node): + """Annotate a node with the stack frame describing the + SConscript file and line number that created it.""" + tb = sys.exc_info()[2] + while tb and stack_bottom not in tb.tb_frame.f_locals: + tb = tb.tb_next + if not tb: + # We did not find any exec of an SConscript file: what?! + raise SCons.Errors.InternalError("could not find SConscript stack frame") + node.creator = traceback.extract_stack(tb)[0] + +# The following line would cause each Node to be annotated using the +# above function. Unfortunately, this is a *huge* performance hit, so +# leave this disabled until we find a more efficient mechanism. +#SCons.Node.Annotate = annotate + +class SConsEnvironment(SCons.Environment.Base): + """An Environment subclass that contains all of the methods that + are particular to the wrapper SCons interface and which aren't + (or shouldn't be) part of the build engine itself. + + Note that not all of the methods of this class have corresponding + global functions, there are some private methods. + """ + + # + # Private methods of an SConsEnvironment. + # + def _exceeds_version(self, major, minor, v_major, v_minor): + """Return 1 if 'major' and 'minor' are greater than the version + in 'v_major' and 'v_minor', and 0 otherwise.""" + return (major > v_major or (major == v_major and minor > v_minor)) + + def _get_major_minor_revision(self, version_string): + """Split a version string into major, minor and (optionally) + revision parts. + + This is complicated by the fact that a version string can be + something like 3.2b1.""" + version = version_string.split(' ')[0].split('.') + v_major = int(version[0]) + v_minor = int(re.match(r'\d+', version[1]).group()) + if len(version) >= 3: + v_revision = int(re.match(r'\d+', version[2]).group()) + else: + v_revision = 0 + return v_major, v_minor, v_revision + + def _get_SConscript_filenames(self, ls, kw): + """ + Convert the parameters passed to SConscript() calls into a list + of files and export variables. If the parameters are invalid, + throws SCons.Errors.UserError. Returns a tuple (l, e) where l + is a list of SConscript filenames and e is a list of exports. + """ + exports = [] + + if len(ls) == 0: + try: + dirs = kw["dirs"] + except KeyError: + raise SCons.Errors.UserError("Invalid SConscript usage - no parameters") + + if not SCons.Util.is_List(dirs): + dirs = [ dirs ] + dirs = list(map(str, dirs)) + + name = kw.get('name', 'SConscript') + + files = [os.path.join(n, name) for n in dirs] + + elif len(ls) == 1: + + files = ls[0] + + elif len(ls) == 2: + + files = ls[0] + exports = self.Split(ls[1]) + + else: + + raise SCons.Errors.UserError("Invalid SConscript() usage - too many arguments") + + if not SCons.Util.is_List(files): + files = [ files ] + + if kw.get('exports'): + exports.extend(self.Split(kw['exports'])) + + variant_dir = kw.get('variant_dir') or kw.get('build_dir') + if variant_dir: + if len(files) != 1: + raise SCons.Errors.UserError("Invalid SConscript() usage - can only specify one SConscript with a variant_dir") + duplicate = kw.get('duplicate', 1) + src_dir = kw.get('src_dir') + if not src_dir: + src_dir, fname = os.path.split(str(files[0])) + files = [os.path.join(str(variant_dir), fname)] + else: + if not isinstance(src_dir, SCons.Node.Node): + src_dir = self.fs.Dir(src_dir) + fn = files[0] + if not isinstance(fn, SCons.Node.Node): + fn = self.fs.File(fn) + if fn.is_under(src_dir): + # Get path relative to the source directory. + fname = fn.get_path(src_dir) + files = [os.path.join(str(variant_dir), fname)] + else: + files = [fn.get_abspath()] + kw['src_dir'] = variant_dir + self.fs.VariantDir(variant_dir, src_dir, duplicate) + + return (files, exports) + + # + # Public methods of an SConsEnvironment. These get + # entry points in the global namespace so they can be called + # as global functions. + # + + def Configure(self, *args, **kw): + if not SCons.Script.sconscript_reading: + raise SCons.Errors.UserError("Calling Configure from Builders is not supported.") + kw['_depth'] = kw.get('_depth', 0) + 1 + return SCons.Environment.Base.Configure(self, *args, **kw) + + def Default(self, *targets): + SCons.Script._Set_Default_Targets(self, targets) + + def EnsureSConsVersion(self, major, minor, revision=0): + """Exit abnormally if the SCons version is not late enough.""" + # split string to avoid replacement during build process + if SCons.__version__ == '__' + 'VERSION__': + SCons.Warnings.warn(SCons.Warnings.DevelopmentVersionWarning, + "EnsureSConsVersion is ignored for development version") + return + scons_ver = self._get_major_minor_revision(SCons.__version__) + if scons_ver < (major, minor, revision): + if revision: + scons_ver_string = '%d.%d.%d' % (major, minor, revision) + else: + scons_ver_string = '%d.%d' % (major, minor) + print("SCons %s or greater required, but you have SCons %s" % \ + (scons_ver_string, SCons.__version__)) + sys.exit(2) + + def EnsurePythonVersion(self, major, minor): + """Exit abnormally if the Python version is not late enough.""" + if sys.version_info < (major, minor): + v = sys.version.split()[0] + print("Python %d.%d or greater required, but you have Python %s" %(major,minor,v)) + sys.exit(2) + + def Exit(self, value=0): + sys.exit(value) + + def Export(self, *vars, **kw): + for var in vars: + global_exports.update(compute_exports(self.Split(var))) + global_exports.update(kw) + + def GetLaunchDir(self): + global launch_dir + return launch_dir + + def GetOption(self, name): + name = self.subst(name) + return SCons.Script.Main.GetOption(name) + + def Help(self, text, append=False): + text = self.subst(text, raw=1) + SCons.Script.HelpFunction(text, append=append) + + def Import(self, *vars): + try: + frame = call_stack[-1] + globals = frame.globals + exports = frame.exports + for var in vars: + var = self.Split(var) + for v in var: + if v == '*': + globals.update(global_exports) + globals.update(exports) + else: + if v in exports: + globals[v] = exports[v] + else: + globals[v] = global_exports[v] + except KeyError as x: + raise SCons.Errors.UserError("Import of non-existent variable '%s'"%x) + + def SConscript(self, *ls, **kw): + """Execute SCons configuration files. + + Parameters: + *ls (str or list): configuration file(s) to execute. + + Keyword arguments: + dirs (list): execute SConscript in each listed directory. + name (str): execute script 'name' (used only with 'dirs'). + exports (list or dict): locally export variables the + called script(s) can import. + variant_dir (str): mirror sources needed for the build in + a variant directory to allow building in it. + duplicate (bool): physically duplicate sources instead of just + adjusting paths of derived files (used only with 'variant_dir') + (default is True). + must_exist (bool): fail if a requested script is missing + (default is False, default is deprecated). + + Returns: + list of variables returned by the called script + + Raises: + UserError: a script is not found and such exceptions are enabled. + """ + + if 'build_dir' in kw: + msg = """The build_dir keyword has been deprecated; use the variant_dir keyword instead.""" + SCons.Warnings.warn(SCons.Warnings.DeprecatedBuildDirWarning, msg) + def subst_element(x, subst=self.subst): + if SCons.Util.is_List(x): + x = list(map(subst, x)) + else: + x = subst(x) + return x + ls = list(map(subst_element, ls)) + subst_kw = {} + for key, val in kw.items(): + if SCons.Util.is_String(val): + val = self.subst(val) + elif SCons.Util.is_List(val): + result = [] + for v in val: + if SCons.Util.is_String(v): + v = self.subst(v) + result.append(v) + val = result + subst_kw[key] = val + + files, exports = self._get_SConscript_filenames(ls, subst_kw) + subst_kw['exports'] = exports + return _SConscript(self.fs, *files, **subst_kw) + + def SConscriptChdir(self, flag): + global sconscript_chdir + sconscript_chdir = flag + + def SetOption(self, name, value): + name = self.subst(name) + SCons.Script.Main.SetOption(name, value) + +# +# +# +SCons.Environment.Environment = SConsEnvironment + +def Configure(*args, **kw): + if not SCons.Script.sconscript_reading: + raise SCons.Errors.UserError("Calling Configure from Builders is not supported.") + kw['_depth'] = 1 + return SCons.SConf.SConf(*args, **kw) + +# It's very important that the DefaultEnvironmentCall() class stay in this +# file, with the get_calling_namespaces() function, the compute_exports() +# function, the Frame class and the SConsEnvironment.Export() method. +# These things make up the calling stack leading up to the actual global +# Export() or SConscript() call that the user issued. We want to allow +# users to export local variables that they define, like so: +# +# def func(): +# x = 1 +# Export('x') +# +# To support this, the get_calling_namespaces() function assumes that +# the *first* stack frame that's not from this file is the local frame +# for the Export() or SConscript() call. + +_DefaultEnvironmentProxy = None + +def get_DefaultEnvironmentProxy(): + global _DefaultEnvironmentProxy + if not _DefaultEnvironmentProxy: + default_env = SCons.Defaults.DefaultEnvironment() + _DefaultEnvironmentProxy = SCons.Environment.NoSubstitutionProxy(default_env) + return _DefaultEnvironmentProxy + +class DefaultEnvironmentCall(object): + """A class that implements "global function" calls of + Environment methods by fetching the specified method from the + DefaultEnvironment's class. Note that this uses an intermediate + proxy class instead of calling the DefaultEnvironment method + directly so that the proxy can override the subst() method and + thereby prevent expansion of construction variables (since from + the user's point of view this was called as a global function, + with no associated construction environment).""" + def __init__(self, method_name, subst=0): + self.method_name = method_name + if subst: + self.factory = SCons.Defaults.DefaultEnvironment + else: + self.factory = get_DefaultEnvironmentProxy + def __call__(self, *args, **kw): + env = self.factory() + method = getattr(env, self.method_name) + return method(*args, **kw) + + +def BuildDefaultGlobals(): + """ + Create a dictionary containing all the default globals for + SConstruct and SConscript files. + """ + + global GlobalDict + if GlobalDict is None: + GlobalDict = {} + + import SCons.Script + d = SCons.Script.__dict__ + def not_a_module(m, d=d, mtype=type(SCons.Script)): + return not isinstance(d[m], mtype) + for m in filter(not_a_module, dir(SCons.Script)): + GlobalDict[m] = d[m] + + return GlobalDict.copy() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Script/__init__.py b/tools/scons/scons-local-3.0.5/SCons/Script/__init__.py new file mode 100755 index 0000000000..d78e7467c0 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Script/__init__.py @@ -0,0 +1,434 @@ +"""SCons.Script + +This file implements the main() function used by the scons script. + +Architecturally, this *is* the scons script, and will likely only be +called from the external "scons" wrapper. Consequently, anything here +should not be, or be considered, part of the build engine. If it's +something that we expect other software to want to use, it should go in +some other module. If it's specific to the "scons" script invocation, +it goes here. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Script/__init__.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import time +start_time = time.time() + +import collections +import os + +try: + from StringIO import StringIO +except ImportError: + from io import StringIO + +import sys + +# Special chicken-and-egg handling of the "--debug=memoizer" flag: +# +# SCons.Memoize contains a metaclass implementation that affects how +# the other classes are instantiated. The Memoizer may add shim methods +# to classes that have methods that cache computed values in order to +# count and report the hits and misses. +# +# If we wait to enable the Memoization until after we've parsed the +# command line options normally, it will be too late, because the Memoizer +# will have already analyzed the classes that it's Memoizing and decided +# to not add the shims. So we use a special-case, up-front check for +# the "--debug=memoizer" flag and enable Memoizer before we import any +# of the other modules that use it. + +_args = sys.argv + os.environ.get('SCONSFLAGS', '').split() +if "--debug=memoizer" in _args: + import SCons.Memoize + import SCons.Warnings + try: + SCons.Memoize.EnableMemoization() + except SCons.Warnings.Warning: + # Some warning was thrown. Arrange for it to be displayed + # or not after warnings are configured. + from . import Main + exc_type, exc_value, tb = sys.exc_info() + Main.delayed_warnings.append((exc_type, exc_value)) +del _args + +import SCons.Action +import SCons.Builder +import SCons.Environment +import SCons.Node.FS +import SCons.Platform +import SCons.Platform.virtualenv +import SCons.Scanner +import SCons.SConf +import SCons.Subst +import SCons.Tool +import SCons.Util +import SCons.Variables +import SCons.Defaults + +from . import Main + +main = Main.main + +# The following are global class definitions and variables that used to +# live directly in this module back before 0.96.90, when it contained +# a lot of code. Some SConscript files in widely-distributed packages +# (Blender is the specific example) actually reached into SCons.Script +# directly to use some of these. Rather than break those SConscript +# files, we're going to propagate these names into the SCons.Script +# namespace here. +# +# Some of these are commented out because it's *really* unlikely anyone +# used them, but we're going to leave the comment here to try to make +# it obvious what to do if the situation arises. +BuildTask = Main.BuildTask +CleanTask = Main.CleanTask +QuestionTask = Main.QuestionTask +#PrintHelp = Main.PrintHelp +#SConscriptSettableOptions = Main.SConscriptSettableOptions + +AddOption = Main.AddOption +PrintHelp = Main.PrintHelp +GetOption = Main.GetOption +SetOption = Main.SetOption +Progress = Main.Progress +GetBuildFailures = Main.GetBuildFailures + +#keep_going_on_error = Main.keep_going_on_error +#print_dtree = Main.print_dtree +#print_explanations = Main.print_explanations +#print_includes = Main.print_includes +#print_objects = Main.print_objects +#print_time = Main.print_time +#print_tree = Main.print_tree +#memory_stats = Main.memory_stats +#ignore_errors = Main.ignore_errors +#sconscript_time = Main.sconscript_time +#command_time = Main.command_time +#exit_status = Main.exit_status +#profiling = Main.profiling +#repositories = Main.repositories + +# +from . import SConscript +_SConscript = SConscript + +call_stack = _SConscript.call_stack + +# +Action = SCons.Action.Action +AddMethod = SCons.Util.AddMethod +AllowSubstExceptions = SCons.Subst.SetAllowableExceptions +Builder = SCons.Builder.Builder +Configure = _SConscript.Configure +Environment = SCons.Environment.Environment +#OptParser = SCons.SConsOptions.OptParser +FindPathDirs = SCons.Scanner.FindPathDirs +Platform = SCons.Platform.Platform +Virtualenv = SCons.Platform.virtualenv.Virtualenv +Return = _SConscript.Return +Scanner = SCons.Scanner.Base +Tool = SCons.Tool.Tool +WhereIs = SCons.Util.WhereIs + +# +BoolVariable = SCons.Variables.BoolVariable +EnumVariable = SCons.Variables.EnumVariable +ListVariable = SCons.Variables.ListVariable +PackageVariable = SCons.Variables.PackageVariable +PathVariable = SCons.Variables.PathVariable + + +# Action factories. +Chmod = SCons.Defaults.Chmod +Copy = SCons.Defaults.Copy +Delete = SCons.Defaults.Delete +Mkdir = SCons.Defaults.Mkdir +Move = SCons.Defaults.Move +Touch = SCons.Defaults.Touch + +# Pre-made, public scanners. +CScanner = SCons.Tool.CScanner +DScanner = SCons.Tool.DScanner +DirScanner = SCons.Defaults.DirScanner +ProgramScanner = SCons.Tool.ProgramScanner +SourceFileScanner = SCons.Tool.SourceFileScanner + +# Functions we might still convert to Environment methods. +CScan = SCons.Defaults.CScan +DefaultEnvironment = SCons.Defaults.DefaultEnvironment + +# Other variables we provide. +class TargetList(collections.UserList): + def _do_nothing(self, *args, **kw): + pass + def _add_Default(self, list): + self.extend(list) + def _clear(self): + del self[:] + +ARGUMENTS = {} +ARGLIST = [] +BUILD_TARGETS = TargetList() +COMMAND_LINE_TARGETS = [] +DEFAULT_TARGETS = [] + +# BUILD_TARGETS can be modified in the SConscript files. If so, we +# want to treat the modified BUILD_TARGETS list as if they specified +# targets on the command line. To do that, though, we need to know if +# BUILD_TARGETS was modified through "official" APIs or by hand. We do +# this by updating two lists in parallel, the documented BUILD_TARGETS +# list, above, and this internal _build_plus_default targets list which +# should only have "official" API changes. Then Script/Main.py can +# compare these two afterwards to figure out if the user added their +# own targets to BUILD_TARGETS. +_build_plus_default = TargetList() + +def _Add_Arguments(alist): + for arg in alist: + a, b = arg.split('=', 1) + ARGUMENTS[a] = b + ARGLIST.append((a, b)) + +def _Add_Targets(tlist): + if tlist: + COMMAND_LINE_TARGETS.extend(tlist) + BUILD_TARGETS.extend(tlist) + BUILD_TARGETS._add_Default = BUILD_TARGETS._do_nothing + BUILD_TARGETS._clear = BUILD_TARGETS._do_nothing + _build_plus_default.extend(tlist) + _build_plus_default._add_Default = _build_plus_default._do_nothing + _build_plus_default._clear = _build_plus_default._do_nothing + +def _Set_Default_Targets_Has_Been_Called(d, fs): + return DEFAULT_TARGETS + +def _Set_Default_Targets_Has_Not_Been_Called(d, fs): + if d is None: + d = [fs.Dir('.')] + return d + +_Get_Default_Targets = _Set_Default_Targets_Has_Not_Been_Called + +def _Set_Default_Targets(env, tlist): + global DEFAULT_TARGETS + global _Get_Default_Targets + _Get_Default_Targets = _Set_Default_Targets_Has_Been_Called + for t in tlist: + if t is None: + # Delete the elements from the list in-place, don't + # reassign an empty list to DEFAULT_TARGETS, so that the + # variables will still point to the same object we point to. + del DEFAULT_TARGETS[:] + BUILD_TARGETS._clear() + _build_plus_default._clear() + elif isinstance(t, SCons.Node.Node): + DEFAULT_TARGETS.append(t) + BUILD_TARGETS._add_Default([t]) + _build_plus_default._add_Default([t]) + else: + nodes = env.arg2nodes(t, env.fs.Entry) + DEFAULT_TARGETS.extend(nodes) + BUILD_TARGETS._add_Default(nodes) + _build_plus_default._add_Default(nodes) + +# +help_text = None + +def HelpFunction(text, append=False): + global help_text + if help_text is None: + if append: + s = StringIO() + PrintHelp(s) + help_text = s.getvalue() + s.close() + else: + help_text = "" + + help_text= help_text + text + + +# +# Will be non-zero if we are reading an SConscript file. +sconscript_reading = 0 + +_no_missing_sconscript = False +_warn_missing_sconscript_deprecated = True + +def set_missing_sconscript_error(flag=1): + """Set behavior on missing file in SConscript() call. Returns previous value""" + global _no_missing_sconscript + old = _no_missing_sconscript + _no_missing_sconscript = flag + return old + +# +def Variables(files=[], args=ARGUMENTS): + return SCons.Variables.Variables(files, args) + + +# The list of global functions to add to the SConscript name space +# that end up calling corresponding methods or Builders in the +# DefaultEnvironment(). +GlobalDefaultEnvironmentFunctions = [ + # Methods from the SConsEnvironment class, above. + 'Default', + 'EnsurePythonVersion', + 'EnsureSConsVersion', + 'Exit', + 'Export', + 'GetLaunchDir', + 'Help', + 'Import', + #'SConscript', is handled separately, below. + 'SConscriptChdir', + + # Methods from the Environment.Base class. + 'AddPostAction', + 'AddPreAction', + 'Alias', + 'AlwaysBuild', + 'BuildDir', + 'CacheDir', + 'Clean', + #The Command() method is handled separately, below. + 'Decider', + 'Depends', + 'Dir', + 'NoClean', + 'NoCache', + 'Entry', + 'Execute', + 'File', + 'FindFile', + 'FindInstalledFiles', + 'FindSourceFiles', + 'Flatten', + 'GetBuildPath', + 'Glob', + 'Ignore', + 'Install', + 'InstallAs', + 'InstallVersionedLib', + 'Literal', + 'Local', + 'ParseDepends', + 'Precious', + 'PyPackageDir', + 'Repository', + 'Requires', + 'SConsignFile', + 'SideEffect', + 'SourceCode', + 'SourceSignatures', + 'Split', + 'Tag', + 'TargetSignatures', + 'Value', + 'VariantDir', +] + +GlobalDefaultBuilders = [ + # Supported builders. + 'CFile', + 'CXXFile', + 'DVI', + 'Jar', + 'Java', + 'JavaH', + 'Library', + 'LoadableModule', + 'M4', + 'MSVSProject', + 'Object', + 'PCH', + 'PDF', + 'PostScript', + 'Program', + 'RES', + 'RMIC', + 'SharedLibrary', + 'SharedObject', + 'StaticLibrary', + 'StaticObject', + 'Substfile', + 'Tar', + 'Textfile', + 'TypeLibrary', + 'Zip', + 'Package', +] + +for name in GlobalDefaultEnvironmentFunctions + GlobalDefaultBuilders: + exec ("%s = _SConscript.DefaultEnvironmentCall(%s)" % (name, repr(name))) +del name + +# There are a handful of variables that used to live in the +# Script/SConscript.py module that some SConscript files out there were +# accessing directly as SCons.Script.SConscript.*. The problem is that +# "SConscript" in this namespace is no longer a module, it's a global +# function call--or more precisely, an object that implements a global +# function call through the default Environment. Nevertheless, we can +# maintain backwards compatibility for SConscripts that were reaching in +# this way by hanging some attributes off the "SConscript" object here. +SConscript = _SConscript.DefaultEnvironmentCall('SConscript') + +# Make SConscript look enough like the module it used to be so +# that pychecker doesn't barf. +SConscript.__name__ = 'SConscript' + +SConscript.Arguments = ARGUMENTS +SConscript.ArgList = ARGLIST +SConscript.BuildTargets = BUILD_TARGETS +SConscript.CommandLineTargets = COMMAND_LINE_TARGETS +SConscript.DefaultTargets = DEFAULT_TARGETS + +# The global Command() function must be handled differently than the +# global functions for other construction environment methods because +# we want people to be able to use Actions that must expand $TARGET +# and $SOURCE later, when (and if) the Action is invoked to build +# the target(s). We do this with the subst=1 argument, which creates +# a DefaultEnvironmentCall instance that wraps up a normal default +# construction environment that performs variable substitution, not a +# proxy that doesn't. +# +# There's a flaw here, though, because any other $-variables on a command +# line will *also* be expanded, each to a null string, but that should +# only be a problem in the unusual case where someone was passing a '$' +# on a command line and *expected* the $ to get through to the shell +# because they were calling Command() and not env.Command()... This is +# unlikely enough that we're going to leave this as is and cross that +# bridge if someone actually comes to it. +Command = _SConscript.DefaultEnvironmentCall('Command', subst=1) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Subst.py b/tools/scons/scons-local-3.0.5/SCons/Subst.py new file mode 100755 index 0000000000..5fae669a71 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Subst.py @@ -0,0 +1,932 @@ +"""SCons.Subst + +SCons string substitution. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +__revision__ = "src/engine/SCons/Subst.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import collections +import re + +import SCons.Errors + +from SCons.Util import is_String, is_Sequence + +# Indexed by the SUBST_* constants below. +_strconv = [SCons.Util.to_String_for_subst, + SCons.Util.to_String_for_subst, + SCons.Util.to_String_for_signature] + + + +AllowableExceptions = (IndexError, NameError) + +def SetAllowableExceptions(*excepts): + global AllowableExceptions + AllowableExceptions = [_f for _f in excepts if _f] + +def raise_exception(exception, target, s): + name = exception.__class__.__name__ + msg = "%s `%s' trying to evaluate `%s'" % (name, exception, s) + if target: + raise SCons.Errors.BuildError(target[0], msg) + else: + raise SCons.Errors.UserError(msg) + + + +class Literal(object): + """A wrapper for a string. If you use this object wrapped + around a string, then it will be interpreted as literal. + When passed to the command interpreter, all special + characters will be escaped.""" + def __init__(self, lstr): + self.lstr = lstr + + def __str__(self): + return self.lstr + + def escape(self, escape_func): + return escape_func(self.lstr) + + def for_signature(self): + return self.lstr + + def is_literal(self): + return 1 + + def __eq__(self, other): + if not isinstance(other, Literal): + return False + return self.lstr == other.lstr + + def __neq__(self, other): + return not self.__eq__(other) + + def __hash__(self): + return hash(self.lstr) + +class SpecialAttrWrapper(object): + """This is a wrapper for what we call a 'Node special attribute.' + This is any of the attributes of a Node that we can reference from + Environment variable substitution, such as $TARGET.abspath or + $SOURCES[1].filebase. We implement the same methods as Literal + so we can handle special characters, plus a for_signature method, + such that we can return some canonical string during signature + calculation to avoid unnecessary rebuilds.""" + + def __init__(self, lstr, for_signature=None): + """The for_signature parameter, if supplied, will be the + canonical string we return from for_signature(). Else + we will simply return lstr.""" + self.lstr = lstr + if for_signature: + self.forsig = for_signature + else: + self.forsig = lstr + + def __str__(self): + return self.lstr + + def escape(self, escape_func): + return escape_func(self.lstr) + + def for_signature(self): + return self.forsig + + def is_literal(self): + return 1 + +def quote_spaces(arg): + """Generic function for putting double quotes around any string that + has white space in it.""" + if ' ' in arg or '\t' in arg: + return '"%s"' % arg + else: + return str(arg) + +class CmdStringHolder(collections.UserString): + """This is a special class used to hold strings generated by + scons_subst() and scons_subst_list(). It defines a special method + escape(). When passed a function with an escape algorithm for a + particular platform, it will return the contained string with the + proper escape sequences inserted. + """ + def __init__(self, cmd, literal=None): + collections.UserString.__init__(self, cmd) + self.literal = literal + + def is_literal(self): + return self.literal + + def escape(self, escape_func, quote_func=quote_spaces): + """Escape the string with the supplied function. The + function is expected to take an arbitrary string, then + return it with all special characters escaped and ready + for passing to the command interpreter. + + After calling this function, the next call to str() will + return the escaped string. + """ + + if self.is_literal(): + return escape_func(self.data) + elif ' ' in self.data or '\t' in self.data: + return quote_func(self.data) + else: + return self.data + +def escape_list(mylist, escape_func): + """Escape a list of arguments by running the specified escape_func + on every object in the list that has an escape() method.""" + def escape(obj, escape_func=escape_func): + try: + e = obj.escape + except AttributeError: + return obj + else: + return e(escape_func) + return list(map(escape, mylist)) + +class NLWrapper(object): + """A wrapper class that delays turning a list of sources or targets + into a NodeList until it's needed. The specified function supplied + when the object is initialized is responsible for turning raw nodes + into proxies that implement the special attributes like .abspath, + .source, etc. This way, we avoid creating those proxies just + "in case" someone is going to use $TARGET or the like, and only + go through the trouble if we really have to. + + In practice, this might be a wash performance-wise, but it's a little + cleaner conceptually... + """ + + def __init__(self, list, func): + self.list = list + self.func = func + def _return_nodelist(self): + return self.nodelist + def _gen_nodelist(self): + mylist = self.list + if mylist is None: + mylist = [] + elif not is_Sequence(mylist): + mylist = [mylist] + # The map(self.func) call is what actually turns + # a list into appropriate proxies. + self.nodelist = SCons.Util.NodeList(list(map(self.func, mylist))) + self._create_nodelist = self._return_nodelist + return self.nodelist + _create_nodelist = _gen_nodelist + + +class Targets_or_Sources(collections.UserList): + """A class that implements $TARGETS or $SOURCES expansions by in turn + wrapping a NLWrapper. This class handles the different methods used + to access the list, calling the NLWrapper to create proxies on demand. + + Note that we subclass collections.UserList purely so that the + is_Sequence() function will identify an object of this class as + a list during variable expansion. We're not really using any + collections.UserList methods in practice. + """ + def __init__(self, nl): + self.nl = nl + def __getattr__(self, attr): + nl = self.nl._create_nodelist() + return getattr(nl, attr) + def __getitem__(self, i): + nl = self.nl._create_nodelist() + return nl[i] + def __getslice__(self, i, j): + nl = self.nl._create_nodelist() + i = max(i, 0); j = max(j, 0) + return nl[i:j] + def __str__(self): + nl = self.nl._create_nodelist() + return str(nl) + def __repr__(self): + nl = self.nl._create_nodelist() + return repr(nl) + +class Target_or_Source(object): + """A class that implements $TARGET or $SOURCE expansions by in turn + wrapping a NLWrapper. This class handles the different methods used + to access an individual proxy Node, calling the NLWrapper to create + a proxy on demand. + """ + def __init__(self, nl): + self.nl = nl + def __getattr__(self, attr): + nl = self.nl._create_nodelist() + try: + nl0 = nl[0] + except IndexError: + # If there is nothing in the list, then we have no attributes to + # pass through, so raise AttributeError for everything. + raise AttributeError("NodeList has no attribute: %s" % attr) + return getattr(nl0, attr) + def __str__(self): + nl = self.nl._create_nodelist() + if nl: + return str(nl[0]) + return '' + def __repr__(self): + nl = self.nl._create_nodelist() + if nl: + return repr(nl[0]) + return '' + +class NullNodeList(SCons.Util.NullSeq): + def __call__(self, *args, **kwargs): return '' + def __str__(self): return '' + +NullNodesList = NullNodeList() + +def subst_dict(target, source): + """Create a dictionary for substitution of special + construction variables. + + This translates the following special arguments: + + target - the target (object or array of objects), + used to generate the TARGET and TARGETS + construction variables + + source - the source (object or array of objects), + used to generate the SOURCES and SOURCE + construction variables + """ + dict = {} + + if target: + def get_tgt_subst_proxy(thing): + try: + subst_proxy = thing.get_subst_proxy() + except AttributeError: + subst_proxy = thing # probably a string, just return it + return subst_proxy + tnl = NLWrapper(target, get_tgt_subst_proxy) + dict['TARGETS'] = Targets_or_Sources(tnl) + dict['TARGET'] = Target_or_Source(tnl) + + # This is a total cheat, but hopefully this dictionary goes + # away soon anyway. We just let these expand to $TARGETS + # because that's "good enough" for the use of ToolSurrogates + # (see test/ToolSurrogate.py) to generate documentation. + dict['CHANGED_TARGETS'] = '$TARGETS' + dict['UNCHANGED_TARGETS'] = '$TARGETS' + else: + dict['TARGETS'] = NullNodesList + dict['TARGET'] = NullNodesList + + if source: + def get_src_subst_proxy(node): + try: + rfile = node.rfile + except AttributeError: + pass + else: + node = rfile() + try: + return node.get_subst_proxy() + except AttributeError: + return node # probably a String, just return it + snl = NLWrapper(source, get_src_subst_proxy) + dict['SOURCES'] = Targets_or_Sources(snl) + dict['SOURCE'] = Target_or_Source(snl) + + # This is a total cheat, but hopefully this dictionary goes + # away soon anyway. We just let these expand to $TARGETS + # because that's "good enough" for the use of ToolSurrogates + # (see test/ToolSurrogate.py) to generate documentation. + dict['CHANGED_SOURCES'] = '$SOURCES' + dict['UNCHANGED_SOURCES'] = '$SOURCES' + else: + dict['SOURCES'] = NullNodesList + dict['SOURCE'] = NullNodesList + + return dict + +# Constants for the "mode" parameter to scons_subst_list() and +# scons_subst(). SUBST_RAW gives the raw command line. SUBST_CMD +# gives a command line suitable for passing to a shell. SUBST_SIG +# gives a command line appropriate for calculating the signature +# of a command line...if this changes, we should rebuild. +SUBST_CMD = 0 +SUBST_RAW = 1 +SUBST_SIG = 2 + +_rm = re.compile(r'\$[()]') + +# Note the pattern below only matches $( or $) when there is no +# preceeding $. (Thus the (?= 0: + if key[0] == '{': + key = key[1:-1] + try: + s = eval(key, self.gvars, lvars) + except KeyboardInterrupt: + raise + except Exception as e: + if e.__class__ in AllowableExceptions: + return + raise_exception(e, lvars['TARGETS'], s) + else: + if key in lvars: + s = lvars[key] + elif key in self.gvars: + s = self.gvars[key] + elif not NameError in AllowableExceptions: + raise_exception(NameError(), lvars['TARGETS'], s) + else: + return + + # Before re-expanding the result, handle + # recursive expansion by copying the local + # variable dictionary and overwriting a null + # string for the value of the variable name + # we just expanded. + lv = lvars.copy() + var = key.split('.')[0] + lv[var] = '' + self.substitute(s, lv, 0) + self.this_word() + elif is_Sequence(s): + for a in s: + self.substitute(a, lvars, 1) + self.next_word() + elif callable(s): + try: + s = s(target=lvars['TARGETS'], + source=lvars['SOURCES'], + env=self.env, + for_signature=(self.mode != SUBST_CMD)) + except TypeError: + # This probably indicates that it's a callable + # object that doesn't match our calling arguments + # (like an Action). + if self.mode == SUBST_RAW: + self.append(s) + return + s = self.conv(s) + self.substitute(s, lvars, within_list) + elif s is None: + self.this_word() + else: + self.append(s) + + def substitute(self, args, lvars, within_list): + """Substitute expansions in an argument or list of arguments. + + This serves as a wrapper for splitting up a string into + separate tokens. + """ + + if is_String(args) and not isinstance(args, CmdStringHolder): + args = str(args) # In case it's a UserString. + args = _separate_args.findall(args) + for a in args: + if a[0] in ' \t\n\r\f\v': + if '\n' in a: + self.next_line() + elif within_list: + self.append(a) + else: + self.next_word() + else: + self.expand(a, lvars, within_list) + else: + self.expand(args, lvars, within_list) + + def next_line(self): + """Arrange for the next word to start a new line. This + is like starting a new word, except that we have to append + another line to the result.""" + collections.UserList.append(self, []) + self.next_word() + + def this_word(self): + """Arrange for the next word to append to the end of the + current last word in the result.""" + self.append = self.add_to_current_word + + def next_word(self): + """Arrange for the next word to start a new word.""" + self.append = self.add_new_word + + def add_to_current_word(self, x): + """Append the string x to the end of the current last word + in the result. If that is not possible, then just add + it as a new word. Make sure the entire concatenated string + inherits the object attributes of x (in particular, the + escape function) by wrapping it as CmdStringHolder.""" + + if not self.in_strip or self.mode != SUBST_SIG: + try: + current_word = self[-1][-1] + except IndexError: + self.add_new_word(x) + else: + # All right, this is a hack and it should probably + # be refactored out of existence in the future. + # The issue is that we want to smoosh words together + # and make one file name that gets escaped if + # we're expanding something like foo$EXTENSION, + # but we don't want to smoosh them together if + # it's something like >$TARGET, because then we'll + # treat the '>' like it's part of the file name. + # So for now, just hard-code looking for the special + # command-line redirection characters... + try: + last_char = str(current_word)[-1] + except IndexError: + last_char = '\0' + if last_char in '<>|': + self.add_new_word(x) + else: + y = current_word + x + + # We used to treat a word appended to a literal + # as a literal itself, but this caused problems + # with interpreting quotes around space-separated + # targets on command lines. Removing this makes + # none of the "substantive" end-to-end tests fail, + # so we'll take this out but leave it commented + # for now in case there's a problem not covered + # by the test cases and we need to resurrect this. + #literal1 = self.literal(self[-1][-1]) + #literal2 = self.literal(x) + y = self.conv(y) + if is_String(y): + #y = CmdStringHolder(y, literal1 or literal2) + y = CmdStringHolder(y, None) + self[-1][-1] = y + + def add_new_word(self, x): + if not self.in_strip or self.mode != SUBST_SIG: + literal = self.literal(x) + x = self.conv(x) + if is_String(x): + x = CmdStringHolder(x, literal) + self[-1].append(x) + self.append = self.add_to_current_word + + def literal(self, x): + try: + l = x.is_literal + except AttributeError: + return None + else: + return l() + + def open_strip(self, x): + """Handle the "open strip" $( token.""" + self.add_strip(x) + self.in_strip = 1 + + def close_strip(self, x): + """Handle the "close strip" $) token.""" + self.add_strip(x) + self.in_strip = None + + if conv is None: + conv = _strconv[mode] + + # Doing this every time is a bit of a waste, since the Executor + # has typically already populated the OverrideEnvironment with + # $TARGET/$SOURCE variables. We're keeping this (for now), though, + # because it supports existing behavior that allows us to call + # an Action directly with an arbitrary target+source pair, which + # we use in Tool/tex.py to handle calling $BIBTEX when necessary. + # If we dropped that behavior (or found another way to cover it), + # we could get rid of this call completely and just rely on the + # Executor setting the variables. + if 'TARGET' not in lvars: + d = subst_dict(target, source) + if d: + lvars = lvars.copy() + lvars.update(d) + + # We're (most likely) going to eval() things. If Python doesn't + # find a __builtins__ value in the global dictionary used for eval(), + # it copies the current global values for you. Avoid this by + # setting it explicitly and then deleting, so we don't pollute the + # construction environment Dictionary(ies) that are typically used + # for expansion. + gvars['__builtins__'] = __builtins__ + + ls = ListSubber(env, mode, conv, gvars) + ls.substitute(strSubst, lvars, 0) + + try: + del gvars['__builtins__'] + except KeyError: + pass + + return ls.data + +def scons_subst_once(strSubst, env, key): + """Perform single (non-recursive) substitution of a single + construction variable keyword. + + This is used when setting a variable when copying or overriding values + in an Environment. We want to capture (expand) the old value before + we override it, so people can do things like: + + env2 = env.Clone(CCFLAGS = '$CCFLAGS -g') + + We do this with some straightforward, brute-force code here... + """ + if isinstance(strSubst, str) and strSubst.find('$') < 0: + return strSubst + + matchlist = ['$' + key, '${' + key + '}'] + val = env.get(key, '') + def sub_match(match, val=val, matchlist=matchlist): + a = match.group(1) + if a in matchlist: + a = val + if is_Sequence(a): + return ' '.join(map(str, a)) + else: + return str(a) + + if is_Sequence(strSubst): + result = [] + for arg in strSubst: + if is_String(arg): + if arg in matchlist: + arg = val + if is_Sequence(arg): + result.extend(arg) + else: + result.append(arg) + else: + result.append(_dollar_exps.sub(sub_match, arg)) + else: + result.append(arg) + return result + elif is_String(strSubst): + return _dollar_exps.sub(sub_match, strSubst) + else: + return strSubst + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Taskmaster.py b/tools/scons/scons-local-3.0.5/SCons/Taskmaster.py new file mode 100755 index 0000000000..48a824121f --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Taskmaster.py @@ -0,0 +1,1080 @@ +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +from __future__ import print_function + +import sys + +__doc__ = """ + Generic Taskmaster module for the SCons build engine. + ===================================================== + + This module contains the primary interface(s) between a wrapping user + interface and the SCons build engine. There are two key classes here: + + Taskmaster + ---------- + This is the main engine for walking the dependency graph and + calling things to decide what does or doesn't need to be built. + + Task + ---- + This is the base class for allowing a wrapping interface to + decide what does or doesn't actually need to be done. The + intention is for a wrapping interface to subclass this as + appropriate for different types of behavior it may need. + + The canonical example is the SCons native Python interface, + which has Task subclasses that handle its specific behavior, + like printing "'foo' is up to date" when a top-level target + doesn't need to be built, and handling the -c option by removing + targets as its "build" action. There is also a separate subclass + for suppressing this output when the -q option is used. + + The Taskmaster instantiates a Task object for each (set of) + target(s) that it decides need to be evaluated and/or built. +""" + +__revision__ = "src/engine/SCons/Taskmaster.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +from itertools import chain +import operator +import sys +import traceback + +import SCons.Errors +import SCons.Node +import SCons.Warnings + +StateString = SCons.Node.StateString +NODE_NO_STATE = SCons.Node.no_state +NODE_PENDING = SCons.Node.pending +NODE_EXECUTING = SCons.Node.executing +NODE_UP_TO_DATE = SCons.Node.up_to_date +NODE_EXECUTED = SCons.Node.executed +NODE_FAILED = SCons.Node.failed + +print_prepare = 0 # set by option --debug=prepare + +# A subsystem for recording stats about how different Nodes are handled by +# the main Taskmaster loop. There's no external control here (no need for +# a --debug= option); enable it by changing the value of CollectStats. + +CollectStats = None + +class Stats(object): + """ + A simple class for holding statistics about the disposition of a + Node by the Taskmaster. If we're collecting statistics, each Node + processed by the Taskmaster gets one of these attached, in which case + the Taskmaster records its decision each time it processes the Node. + (Ideally, that's just once per Node.) + """ + def __init__(self): + """ + Instantiates a Taskmaster.Stats object, initializing all + appropriate counters to zero. + """ + self.considered = 0 + self.already_handled = 0 + self.problem = 0 + self.child_failed = 0 + self.not_built = 0 + self.side_effects = 0 + self.build = 0 + +StatsNodes = [] + +fmt = "%(considered)3d "\ + "%(already_handled)3d " \ + "%(problem)3d " \ + "%(child_failed)3d " \ + "%(not_built)3d " \ + "%(side_effects)3d " \ + "%(build)3d " + +def dump_stats(): + for n in sorted(StatsNodes, key=lambda a: str(a)): + print((fmt % n.attributes.stats.__dict__) + str(n)) + + + +class Task(object): + """ + Default SCons build engine task. + + This controls the interaction of the actual building of node + and the rest of the engine. + + This is expected to handle all of the normally-customizable + aspects of controlling a build, so any given application + *should* be able to do what it wants by sub-classing this + class and overriding methods as appropriate. If an application + needs to customize something by sub-classing Taskmaster (or + some other build engine class), we should first try to migrate + that functionality into this class. + + Note that it's generally a good idea for sub-classes to call + these methods explicitly to update state, etc., rather than + roll their own interaction with Taskmaster from scratch. + """ + def __init__(self, tm, targets, top, node): + self.tm = tm + self.targets = targets + self.top = top + self.node = node + self.exc_clear() + + def trace_message(self, method, node, description='node'): + fmt = '%-20s %s %s\n' + return fmt % (method + ':', description, self.tm.trace_node(node)) + + def display(self, message): + """ + Hook to allow the calling interface to display a message. + + This hook gets called as part of preparing a task for execution + (that is, a Node to be built). As part of figuring out what Node + should be built next, the actual target list may be altered, + along with a message describing the alteration. The calling + interface can subclass Task and provide a concrete implementation + of this method to see those messages. + """ + pass + + def prepare(self): + """ + Called just before the task is executed. + + This is mainly intended to give the target Nodes a chance to + unlink underlying files and make all necessary directories before + the Action is actually called to build the targets. + """ + global print_prepare + T = self.tm.trace + if T: T.write(self.trace_message(u'Task.prepare()', self.node)) + + # Now that it's the appropriate time, give the TaskMaster a + # chance to raise any exceptions it encountered while preparing + # this task. + self.exception_raise() + + if self.tm.message: + self.display(self.tm.message) + self.tm.message = None + + # Let the targets take care of any necessary preparations. + # This includes verifying that all of the necessary sources + # and dependencies exist, removing the target file(s), etc. + # + # As of April 2008, the get_executor().prepare() method makes + # sure that all of the aggregate sources necessary to build this + # Task's target(s) exist in one up-front check. The individual + # target t.prepare() methods check that each target's explicit + # or implicit dependencies exists, and also initialize the + # .sconsign info. + executor = self.targets[0].get_executor() + if executor is None: + return + executor.prepare() + for t in executor.get_action_targets(): + if print_prepare: + print("Preparing target %s..."%t) + for s in t.side_effects: + print("...with side-effect %s..."%s) + t.prepare() + for s in t.side_effects: + if print_prepare: + print("...Preparing side-effect %s..."%s) + s.prepare() + + def get_target(self): + """Fetch the target being built or updated by this task. + """ + return self.node + + def needs_execute(self): + # TODO(deprecate): "return True" is the old default behavior; + # change it to NotImplementedError (after running through the + # Deprecation Cycle) so the desired behavior is explicitly + # determined by which concrete subclass is used. + #raise NotImplementedError + msg = ('Taskmaster.Task is an abstract base class; instead of\n' + '\tusing it directly, ' + 'derive from it and override the abstract methods.') + SCons.Warnings.warn(SCons.Warnings.TaskmasterNeedsExecuteWarning, msg) + return True + + def execute(self): + """ + Called to execute the task. + + This method is called from multiple threads in a parallel build, + so only do thread safe stuff here. Do thread unsafe stuff in + prepare(), executed() or failed(). + """ + T = self.tm.trace + if T: T.write(self.trace_message(u'Task.execute()', self.node)) + + try: + cached_targets = [] + for t in self.targets: + if not t.retrieve_from_cache(): + break + cached_targets.append(t) + if len(cached_targets) < len(self.targets): + # Remove targets before building. It's possible that we + # partially retrieved targets from the cache, leaving + # them in read-only mode. That might cause the command + # to fail. + # + for t in cached_targets: + try: + t.fs.unlink(t.get_internal_path()) + except (IOError, OSError): + pass + self.targets[0].build() + else: + for t in cached_targets: + t.cached = 1 + except SystemExit: + exc_value = sys.exc_info()[1] + raise SCons.Errors.ExplicitExit(self.targets[0], exc_value.code) + except SCons.Errors.UserError: + raise + except SCons.Errors.BuildError: + raise + except Exception as e: + buildError = SCons.Errors.convert_to_BuildError(e) + buildError.node = self.targets[0] + buildError.exc_info = sys.exc_info() + raise buildError + + def executed_without_callbacks(self): + """ + Called when the task has been successfully executed + and the Taskmaster instance doesn't want to call + the Node's callback methods. + """ + T = self.tm.trace + if T: T.write(self.trace_message('Task.executed_without_callbacks()', + self.node)) + + for t in self.targets: + if t.get_state() == NODE_EXECUTING: + for side_effect in t.side_effects: + side_effect.set_state(NODE_NO_STATE) + t.set_state(NODE_EXECUTED) + + def executed_with_callbacks(self): + """ + Called when the task has been successfully executed and + the Taskmaster instance wants to call the Node's callback + methods. + + This may have been a do-nothing operation (to preserve build + order), so we must check the node's state before deciding whether + it was "built", in which case we call the appropriate Node method. + In any event, we always call "visited()", which will handle any + post-visit actions that must take place regardless of whether + or not the target was an actual built target or a source Node. + """ + global print_prepare + T = self.tm.trace + if T: T.write(self.trace_message('Task.executed_with_callbacks()', + self.node)) + + for t in self.targets: + if t.get_state() == NODE_EXECUTING: + for side_effect in t.side_effects: + side_effect.set_state(NODE_NO_STATE) + t.set_state(NODE_EXECUTED) + if not t.cached: + t.push_to_cache() + t.built() + t.visited() + if (not print_prepare and + (not hasattr(self, 'options') or not self.options.debug_includes)): + t.release_target_info() + else: + t.visited() + + executed = executed_with_callbacks + + def failed(self): + """ + Default action when a task fails: stop the build. + + Note: Although this function is normally invoked on nodes in + the executing state, it might also be invoked on up-to-date + nodes when using Configure(). + """ + self.fail_stop() + + def fail_stop(self): + """ + Explicit stop-the-build failure. + + This sets failure status on the target nodes and all of + their dependent parent nodes. + + Note: Although this function is normally invoked on nodes in + the executing state, it might also be invoked on up-to-date + nodes when using Configure(). + """ + T = self.tm.trace + if T: T.write(self.trace_message('Task.failed_stop()', self.node)) + + # Invoke will_not_build() to clean-up the pending children + # list. + self.tm.will_not_build(self.targets, lambda n: n.set_state(NODE_FAILED)) + + # Tell the taskmaster to not start any new tasks + self.tm.stop() + + # We're stopping because of a build failure, but give the + # calling Task class a chance to postprocess() the top-level + # target under which the build failure occurred. + self.targets = [self.tm.current_top] + self.top = 1 + + def fail_continue(self): + """ + Explicit continue-the-build failure. + + This sets failure status on the target nodes and all of + their dependent parent nodes. + + Note: Although this function is normally invoked on nodes in + the executing state, it might also be invoked on up-to-date + nodes when using Configure(). + """ + T = self.tm.trace + if T: T.write(self.trace_message('Task.failed_continue()', self.node)) + + self.tm.will_not_build(self.targets, lambda n: n.set_state(NODE_FAILED)) + + def make_ready_all(self): + """ + Marks all targets in a task ready for execution. + + This is used when the interface needs every target Node to be + visited--the canonical example being the "scons -c" option. + """ + T = self.tm.trace + if T: T.write(self.trace_message('Task.make_ready_all()', self.node)) + + self.out_of_date = self.targets[:] + for t in self.targets: + t.disambiguate().set_state(NODE_EXECUTING) + for s in t.side_effects: + # add disambiguate here to mirror the call on targets above + s.disambiguate().set_state(NODE_EXECUTING) + + def make_ready_current(self): + """ + Marks all targets in a task ready for execution if any target + is not current. + + This is the default behavior for building only what's necessary. + """ + global print_prepare + T = self.tm.trace + if T: T.write(self.trace_message(u'Task.make_ready_current()', + self.node)) + + self.out_of_date = [] + needs_executing = False + for t in self.targets: + try: + t.disambiguate().make_ready() + is_up_to_date = not t.has_builder() or \ + (not t.always_build and t.is_up_to_date()) + except EnvironmentError as e: + raise SCons.Errors.BuildError(node=t, errstr=e.strerror, filename=e.filename) + + if not is_up_to_date: + self.out_of_date.append(t) + needs_executing = True + + if needs_executing: + for t in self.targets: + t.set_state(NODE_EXECUTING) + for s in t.side_effects: + # add disambiguate here to mirror the call on targets in first loop above + s.disambiguate().set_state(NODE_EXECUTING) + else: + for t in self.targets: + # We must invoke visited() to ensure that the node + # information has been computed before allowing the + # parent nodes to execute. (That could occur in a + # parallel build...) + t.visited() + t.set_state(NODE_UP_TO_DATE) + if (not print_prepare and + (not hasattr(self, 'options') or not self.options.debug_includes)): + t.release_target_info() + + make_ready = make_ready_current + + def postprocess(self): + """ + Post-processes a task after it's been executed. + + This examines all the targets just built (or not, we don't care + if the build was successful, or even if there was no build + because everything was up-to-date) to see if they have any + waiting parent Nodes, or Nodes waiting on a common side effect, + that can be put back on the candidates list. + """ + T = self.tm.trace + if T: T.write(self.trace_message(u'Task.postprocess()', self.node)) + + # We may have built multiple targets, some of which may have + # common parents waiting for this build. Count up how many + # targets each parent was waiting for so we can subtract the + # values later, and so we *don't* put waiting side-effect Nodes + # back on the candidates list if the Node is also a waiting + # parent. + + targets = set(self.targets) + + pending_children = self.tm.pending_children + parents = {} + for t in targets: + # A node can only be in the pending_children set if it has + # some waiting_parents. + if t.waiting_parents: + if T: T.write(self.trace_message(u'Task.postprocess()', + t, + 'removing')) + pending_children.discard(t) + for p in t.waiting_parents: + parents[p] = parents.get(p, 0) + 1 + t.waiting_parents = set() + + for t in targets: + if t.side_effects is not None: + for s in t.side_effects: + if s.get_state() == NODE_EXECUTING: + s.set_state(NODE_NO_STATE) + + # The side-effects may have been transferred to + # NODE_NO_STATE by executed_with{,out}_callbacks, but was + # not taken out of the waiting parents/pending children + # data structures. Check for that now. + if s.get_state() == NODE_NO_STATE and s.waiting_parents: + pending_children.discard(s) + for p in s.waiting_parents: + parents[p] = parents.get(p, 0) + 1 + s.waiting_parents = set() + for p in s.waiting_s_e: + if p.ref_count == 0: + self.tm.candidates.append(p) + + for p, subtract in parents.items(): + p.ref_count = p.ref_count - subtract + if T: T.write(self.trace_message(u'Task.postprocess()', + p, + 'adjusted parent ref count')) + if p.ref_count == 0: + self.tm.candidates.append(p) + + for t in targets: + t.postprocess() + + # Exception handling subsystem. + # + # Exceptions that occur while walking the DAG or examining Nodes + # must be raised, but must be raised at an appropriate time and in + # a controlled manner so we can, if necessary, recover gracefully, + # possibly write out signature information for Nodes we've updated, + # etc. This is done by having the Taskmaster tell us about the + # exception, and letting + + def exc_info(self): + """ + Returns info about a recorded exception. + """ + return self.exception + + def exc_clear(self): + """ + Clears any recorded exception. + + This also changes the "exception_raise" attribute to point + to the appropriate do-nothing method. + """ + self.exception = (None, None, None) + self.exception_raise = self._no_exception_to_raise + + def exception_set(self, exception=None): + """ + Records an exception to be raised at the appropriate time. + + This also changes the "exception_raise" attribute to point + to the method that will, in fact + """ + if not exception: + exception = sys.exc_info() + self.exception = exception + self.exception_raise = self._exception_raise + + def _no_exception_to_raise(self): + pass + + def _exception_raise(self): + """ + Raises a pending exception that was recorded while getting a + Task ready for execution. + """ + exc = self.exc_info()[:] + try: + exc_type, exc_value, exc_traceback = exc + except ValueError: + exc_type, exc_value = exc + exc_traceback = None + + # raise exc_type(exc_value).with_traceback(exc_traceback) + if sys.version_info[0] == 2: + exec("raise exc_type, exc_value, exc_traceback") + else: # sys.version_info[0] == 3: + if isinstance(exc_value, Exception): #hasattr(exc_value, 'with_traceback'): + # If exc_value is an exception, then just reraise + exec("raise exc_value.with_traceback(exc_traceback)") + else: + # else we'll create an exception using the value and raise that + exec("raise exc_type(exc_value).with_traceback(exc_traceback)") + + + # raise e.__class__, e.__class__(e), sys.exc_info()[2] + # exec("raise exc_type(exc_value).with_traceback(exc_traceback)") + + + +class AlwaysTask(Task): + def needs_execute(self): + """ + Always returns True (indicating this Task should always + be executed). + + Subclasses that need this behavior (as opposed to the default + of only executing Nodes that are out of date w.r.t. their + dependencies) can use this as follows: + + class MyTaskSubclass(SCons.Taskmaster.Task): + needs_execute = SCons.Taskmaster.Task.execute_always + """ + return True + +class OutOfDateTask(Task): + def needs_execute(self): + """ + Returns True (indicating this Task should be executed) if this + Task's target state indicates it needs executing, which has + already been determined by an earlier up-to-date check. + """ + return self.targets[0].get_state() == SCons.Node.executing + + +def find_cycle(stack, visited): + if stack[-1] in visited: + return None + visited.add(stack[-1]) + for n in stack[-1].waiting_parents: + stack.append(n) + if stack[0] == stack[-1]: + return stack + if find_cycle(stack, visited): + return stack + stack.pop() + return None + + +class Taskmaster(object): + """ + The Taskmaster for walking the dependency DAG. + """ + + def __init__(self, targets=[], tasker=None, order=None, trace=None): + self.original_top = targets + self.top_targets_left = targets[:] + self.top_targets_left.reverse() + self.candidates = [] + if tasker is None: + tasker = OutOfDateTask + self.tasker = tasker + if not order: + order = lambda l: l + self.order = order + self.message = None + self.trace = trace + self.next_candidate = self.find_next_candidate + self.pending_children = set() + + def find_next_candidate(self): + """ + Returns the next candidate Node for (potential) evaluation. + + The candidate list (really a stack) initially consists of all of + the top-level (command line) targets provided when the Taskmaster + was initialized. While we walk the DAG, visiting Nodes, all the + children that haven't finished processing get pushed on to the + candidate list. Each child can then be popped and examined in + turn for whether *their* children are all up-to-date, in which + case a Task will be created for their actual evaluation and + potential building. + + Here is where we also allow candidate Nodes to alter the list of + Nodes that should be examined. This is used, for example, when + invoking SCons in a source directory. A source directory Node can + return its corresponding build directory Node, essentially saying, + "Hey, you really need to build this thing over here instead." + """ + try: + return self.candidates.pop() + except IndexError: + pass + try: + node = self.top_targets_left.pop() + except IndexError: + return None + self.current_top = node + alt, message = node.alter_targets() + if alt: + self.message = message + self.candidates.append(node) + self.candidates.extend(self.order(alt)) + node = self.candidates.pop() + return node + + def no_next_candidate(self): + """ + Stops Taskmaster processing by not returning a next candidate. + + Note that we have to clean-up the Taskmaster candidate list + because the cycle detection depends on the fact all nodes have + been processed somehow. + """ + while self.candidates: + candidates = self.candidates + self.candidates = [] + self.will_not_build(candidates) + return None + + def _validate_pending_children(self): + """ + Validate the content of the pending_children set. Assert if an + internal error is found. + + This function is used strictly for debugging the taskmaster by + checking that no invariants are violated. It is not used in + normal operation. + + The pending_children set is used to detect cycles in the + dependency graph. We call a "pending child" a child that is + found in the "pending" state when checking the dependencies of + its parent node. + + A pending child can occur when the Taskmaster completes a loop + through a cycle. For example, let's imagine a graph made of + three nodes (A, B and C) making a cycle. The evaluation starts + at node A. The Taskmaster first considers whether node A's + child B is up-to-date. Then, recursively, node B needs to + check whether node C is up-to-date. This leaves us with a + dependency graph looking like:: + + Next candidate \ + \ + Node A (Pending) --> Node B(Pending) --> Node C (NoState) + ^ | + | | + +-------------------------------------+ + + Now, when the Taskmaster examines the Node C's child Node A, + it finds that Node A is in the "pending" state. Therefore, + Node A is a pending child of node C. + + Pending children indicate that the Taskmaster has potentially + loop back through a cycle. We say potentially because it could + also occur when a DAG is evaluated in parallel. For example, + consider the following graph:: + + Node A (Pending) --> Node B(Pending) --> Node C (Pending) --> ... + | ^ + | | + +----------> Node D (NoState) --------+ + / + Next candidate / + + The Taskmaster first evaluates the nodes A, B, and C and + starts building some children of node C. Assuming, that the + maximum parallel level has not been reached, the Taskmaster + will examine Node D. It will find that Node C is a pending + child of Node D. + + In summary, evaluating a graph with a cycle will always + involve a pending child at one point. A pending child might + indicate either a cycle or a diamond-shaped DAG. Only a + fraction of the nodes ends-up being a "pending child" of + another node. This keeps the pending_children set small in + practice. + + We can differentiate between the two cases if we wait until + the end of the build. At this point, all the pending children + nodes due to a diamond-shaped DAG will have been properly + built (or will have failed to build). But, the pending + children involved in a cycle will still be in the pending + state. + + The taskmaster removes nodes from the pending_children set as + soon as a pending_children node moves out of the pending + state. This also helps to keep the pending_children set small. + """ + + for n in self.pending_children: + assert n.state in (NODE_PENDING, NODE_EXECUTING), \ + (str(n), StateString[n.state]) + assert len(n.waiting_parents) != 0, (str(n), len(n.waiting_parents)) + for p in n.waiting_parents: + assert p.ref_count > 0, (str(n), str(p), p.ref_count) + + + def trace_message(self, message): + return 'Taskmaster: %s\n' % message + + def trace_node(self, node): + return '<%-10s %-3s %s>' % (StateString[node.get_state()], + node.ref_count, + repr(str(node))) + + def _find_next_ready_node(self): + """ + Finds the next node that is ready to be built. + + This is *the* main guts of the DAG walk. We loop through the + list of candidates, looking for something that has no un-built + children (i.e., that is a leaf Node or has dependencies that are + all leaf Nodes or up-to-date). Candidate Nodes are re-scanned + (both the target Node itself and its sources, which are always + scanned in the context of a given target) to discover implicit + dependencies. A Node that must wait for some children to be + built will be put back on the candidates list after the children + have finished building. A Node that has been put back on the + candidates list in this way may have itself (or its sources) + re-scanned, in order to handle generated header files (e.g.) and + the implicit dependencies therein. + + Note that this method does not do any signature calculation or + up-to-date check itself. All of that is handled by the Task + class. This is purely concerned with the dependency graph walk. + """ + + self.ready_exc = None + + T = self.trace + if T: T.write(SCons.Util.UnicodeType('\n') + self.trace_message('Looking for a node to evaluate')) + + while True: + node = self.next_candidate() + if node is None: + if T: T.write(self.trace_message('No candidate anymore.') + u'\n') + return None + + node = node.disambiguate() + state = node.get_state() + + # For debugging only: + # + # try: + # self._validate_pending_children() + # except: + # self.ready_exc = sys.exc_info() + # return node + + if CollectStats: + if not hasattr(node.attributes, 'stats'): + node.attributes.stats = Stats() + StatsNodes.append(node) + S = node.attributes.stats + S.considered = S.considered + 1 + else: + S = None + + if T: T.write(self.trace_message(u' Considering node %s and its children:' % self.trace_node(node))) + + if state == NODE_NO_STATE: + # Mark this node as being on the execution stack: + node.set_state(NODE_PENDING) + elif state > NODE_PENDING: + # Skip this node if it has already been evaluated: + if S: S.already_handled = S.already_handled + 1 + if T: T.write(self.trace_message(u' already handled (executed)')) + continue + + executor = node.get_executor() + + try: + children = executor.get_all_children() + except SystemExit: + exc_value = sys.exc_info()[1] + e = SCons.Errors.ExplicitExit(node, exc_value.code) + self.ready_exc = (SCons.Errors.ExplicitExit, e) + if T: T.write(self.trace_message(' SystemExit')) + return node + except Exception as e: + # We had a problem just trying to figure out the + # children (like a child couldn't be linked in to a + # VariantDir, or a Scanner threw something). Arrange to + # raise the exception when the Task is "executed." + self.ready_exc = sys.exc_info() + if S: S.problem = S.problem + 1 + if T: T.write(self.trace_message(' exception %s while scanning children.\n' % e)) + return node + + children_not_visited = [] + children_pending = set() + children_not_ready = [] + children_failed = False + + for child in chain(executor.get_all_prerequisites(), children): + childstate = child.get_state() + + if T: T.write(self.trace_message(u' ' + self.trace_node(child))) + + if childstate == NODE_NO_STATE: + children_not_visited.append(child) + elif childstate == NODE_PENDING: + children_pending.add(child) + elif childstate == NODE_FAILED: + children_failed = True + + if childstate <= NODE_EXECUTING: + children_not_ready.append(child) + + # These nodes have not even been visited yet. Add + # them to the list so that on some next pass we can + # take a stab at evaluating them (or their children). + children_not_visited.reverse() + self.candidates.extend(self.order(children_not_visited)) + + # if T and children_not_visited: + # T.write(self.trace_message(' adding to candidates: %s' % map(str, children_not_visited))) + # T.write(self.trace_message(' candidates now: %s\n' % map(str, self.candidates))) + + # Skip this node if any of its children have failed. + # + # This catches the case where we're descending a top-level + # target and one of our children failed while trying to be + # built by a *previous* descent of an earlier top-level + # target. + # + # It can also occur if a node is reused in multiple + # targets. One first descends though the one of the + # target, the next time occurs through the other target. + # + # Note that we can only have failed_children if the + # --keep-going flag was used, because without it the build + # will stop before diving in the other branch. + # + # Note that even if one of the children fails, we still + # added the other children to the list of candidate nodes + # to keep on building (--keep-going). + if children_failed: + for n in executor.get_action_targets(): + n.set_state(NODE_FAILED) + + if S: S.child_failed = S.child_failed + 1 + if T: T.write(self.trace_message('****** %s\n' % self.trace_node(node))) + continue + + if children_not_ready: + for child in children_not_ready: + # We're waiting on one or more derived targets + # that have not yet finished building. + if S: S.not_built = S.not_built + 1 + + # Add this node to the waiting parents lists of + # anything we're waiting on, with a reference + # count so we can be put back on the list for + # re-evaluation when they've all finished. + node.ref_count = node.ref_count + child.add_to_waiting_parents(node) + if T: T.write(self.trace_message(u' adjusted ref count: %s, child %s' % + (self.trace_node(node), repr(str(child))))) + + if T: + for pc in children_pending: + T.write(self.trace_message(' adding %s to the pending children set\n' % + self.trace_node(pc))) + self.pending_children = self.pending_children | children_pending + + continue + + # Skip this node if it has side-effects that are + # currently being built: + wait_side_effects = False + for se in executor.get_action_side_effects(): + if se.get_state() == NODE_EXECUTING: + se.add_to_waiting_s_e(node) + wait_side_effects = True + + if wait_side_effects: + if S: S.side_effects = S.side_effects + 1 + continue + + # The default when we've gotten through all of the checks above: + # this node is ready to be built. + if S: S.build = S.build + 1 + if T: T.write(self.trace_message(u'Evaluating %s\n' % + self.trace_node(node))) + + # For debugging only: + # + # try: + # self._validate_pending_children() + # except: + # self.ready_exc = sys.exc_info() + # return node + + return node + + return None + + def next_task(self): + """ + Returns the next task to be executed. + + This simply asks for the next Node to be evaluated, and then wraps + it in the specific Task subclass with which we were initialized. + """ + node = self._find_next_ready_node() + + if node is None: + return None + + executor = node.get_executor() + if executor is None: + return None + + tlist = executor.get_all_targets() + + task = self.tasker(self, tlist, node in self.original_top, node) + try: + task.make_ready() + except Exception as e : + # We had a problem just trying to get this task ready (like + # a child couldn't be linked to a VariantDir when deciding + # whether this node is current). Arrange to raise the + # exception when the Task is "executed." + self.ready_exc = sys.exc_info() + + if self.ready_exc: + task.exception_set(self.ready_exc) + + self.ready_exc = None + + return task + + def will_not_build(self, nodes, node_func=lambda n: None): + """ + Perform clean-up about nodes that will never be built. Invokes + a user defined function on all of these nodes (including all + of their parents). + """ + + T = self.trace + + pending_children = self.pending_children + + to_visit = set(nodes) + pending_children = pending_children - to_visit + + if T: + for n in nodes: + T.write(self.trace_message(' removing node %s from the pending children set\n' % + self.trace_node(n))) + try: + while len(to_visit): + node = to_visit.pop() + node_func(node) + + # Prune recursion by flushing the waiting children + # list immediately. + parents = node.waiting_parents + node.waiting_parents = set() + + to_visit = to_visit | parents + pending_children = pending_children - parents + + for p in parents: + p.ref_count = p.ref_count - 1 + if T: T.write(self.trace_message(' removing parent %s from the pending children set\n' % + self.trace_node(p))) + except KeyError: + # The container to_visit has been emptied. + pass + + # We have the stick back the pending_children list into the + # taskmaster because the python 1.5.2 compatibility does not + # allow us to use in-place updates + self.pending_children = pending_children + + def stop(self): + """ + Stops the current build completely. + """ + self.next_candidate = self.no_next_candidate + + def cleanup(self): + """ + Check for dependency cycles. + """ + if not self.pending_children: + return + + nclist = [(n, find_cycle([n], set())) for n in self.pending_children] + + genuine_cycles = [ + node for node,cycle in nclist + if cycle or node.get_state() != NODE_EXECUTED + ] + if not genuine_cycles: + # All of the "cycles" found were single nodes in EXECUTED state, + # which is to say, they really weren't cycles. Just return. + return + + desc = 'Found dependency cycle(s):\n' + for node, cycle in nclist: + if cycle: + desc = desc + " " + " -> ".join(map(str, cycle)) + "\n" + else: + desc = desc + \ + " Internal Error: no cycle found for node %s (%s) in state %s\n" % \ + (node, repr(node), StateString[node.get_state()]) + + raise SCons.Errors.UserError(desc) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/386asm.py b/tools/scons/scons-local-3.0.5/SCons/Tool/386asm.py new file mode 100755 index 0000000000..c01f09ece9 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/386asm.py @@ -0,0 +1,61 @@ +"""SCons.Tool.386asm + +Tool specification for the 386ASM assembler for the Phar Lap ETS embedded +operating system. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/386asm.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +from SCons.Tool.PharLapCommon import addPharLapPaths +import SCons.Util + +as_module = __import__('as', globals(), locals(), [], 1) + +def generate(env): + """Add Builders and construction variables for ar to an Environment.""" + as_module.generate(env) + + env['AS'] = '386asm' + env['ASFLAGS'] = SCons.Util.CLVar('') + env['ASPPFLAGS'] = '$ASFLAGS' + env['ASCOM'] = '$AS $ASFLAGS $SOURCES -o $TARGET' + env['ASPPCOM'] = '$CC $ASPPFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS $SOURCES -o $TARGET' + + addPharLapPaths(env) + +def exists(env): + return env.Detect('386asm') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/DCommon.py b/tools/scons/scons-local-3.0.5/SCons/Tool/DCommon.py new file mode 100755 index 0000000000..c4e42d0063 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/DCommon.py @@ -0,0 +1,69 @@ +from __future__ import print_function + +"""SCons.Tool.DCommon + +Common code for the various D tools. + +Coded by Russel Winder (russel@winder.org.uk) +2012-09-06 +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/DCommon.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os.path + + +def isD(env, source): + if not source: + return 0 + for s in source: + if s.sources: + ext = os.path.splitext(str(s.sources[0]))[1] + if ext == '.d': + return 1 + return 0 + + +def addDPATHToEnv(env, executable): + dPath = env.WhereIs(executable) + if dPath: + phobosDir = dPath[:dPath.rindex(executable)] + '/../src/phobos' + if os.path.isdir(phobosDir): + env.Append(DPATH=[phobosDir]) + + +def allAtOnceEmitter(target, source, env): + if env['DC'] in ('ldc2', 'dmd'): + env.SideEffect(str(target[0]) + '.o', target[0]) + env.Clean(target[0], str(target[0]) + '.o') + return target, source + + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/FortranCommon.py b/tools/scons/scons-local-3.0.5/SCons/Tool/FortranCommon.py new file mode 100755 index 0000000000..9287396277 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/FortranCommon.py @@ -0,0 +1,280 @@ +"""SCons.Tool.FortranCommon + +Stuff for processing Fortran, common to all fortran dialects. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +from __future__ import print_function + +__revision__ = "src/engine/SCons/Tool/FortranCommon.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import re +import os.path + +import SCons.Action +import SCons.Defaults +import SCons.Scanner.Fortran +import SCons.Tool +import SCons.Util + +def isfortran(env, source): + """Return 1 if any of code in source has fortran files in it, 0 + otherwise.""" + try: + fsuffixes = env['FORTRANSUFFIXES'] + except KeyError: + # If no FORTRANSUFFIXES, no fortran tool, so there is no need to look + # for fortran sources. + return 0 + + if not source: + # Source might be None for unusual cases like SConf. + return 0 + for s in source: + if s.sources: + ext = os.path.splitext(str(s.sources[0]))[1] + if ext in fsuffixes: + return 1 + return 0 + +def _fortranEmitter(target, source, env): + node = source[0].rfile() + if not node.exists() and not node.is_derived(): + print("Could not locate " + str(node.name)) + return ([], []) + mod_regex = """(?i)^\s*MODULE\s+(?!PROCEDURE)(\w+)""" + cre = re.compile(mod_regex,re.M) + # Retrieve all USE'd module names + modules = cre.findall(node.get_text_contents()) + # Remove unique items from the list + modules = SCons.Util.unique(modules) + # Convert module name to a .mod filename + suffix = env.subst('$FORTRANMODSUFFIX', target=target, source=source) + moddir = env.subst('$FORTRANMODDIR', target=target, source=source) + modules = [x.lower() + suffix for x in modules] + for m in modules: + target.append(env.fs.File(m, moddir)) + return (target, source) + +def FortranEmitter(target, source, env): + target, source = _fortranEmitter(target, source, env) + return SCons.Defaults.StaticObjectEmitter(target, source, env) + +def ShFortranEmitter(target, source, env): + target, source = _fortranEmitter(target, source, env) + return SCons.Defaults.SharedObjectEmitter(target, source, env) + +def ComputeFortranSuffixes(suffixes, ppsuffixes): + """suffixes are fortran source files, and ppsuffixes the ones to be + pre-processed. Both should be sequences, not strings.""" + assert len(suffixes) > 0 + s = suffixes[0] + sup = s.upper() + upper_suffixes = [_.upper() for _ in suffixes] + if SCons.Util.case_sensitive_suffixes(s, sup): + ppsuffixes.extend(upper_suffixes) + else: + suffixes.extend(upper_suffixes) + +def CreateDialectActions(dialect): + """Create dialect specific actions.""" + CompAction = SCons.Action.Action('$%sCOM ' % dialect, '$%sCOMSTR' % dialect) + CompPPAction = SCons.Action.Action('$%sPPCOM ' % dialect, '$%sPPCOMSTR' % dialect) + ShCompAction = SCons.Action.Action('$SH%sCOM ' % dialect, '$SH%sCOMSTR' % dialect) + ShCompPPAction = SCons.Action.Action('$SH%sPPCOM ' % dialect, '$SH%sPPCOMSTR' % dialect) + + return CompAction, CompPPAction, ShCompAction, ShCompPPAction + +def DialectAddToEnv(env, dialect, suffixes, ppsuffixes, support_module = 0): + """Add dialect specific construction variables.""" + ComputeFortranSuffixes(suffixes, ppsuffixes) + + fscan = SCons.Scanner.Fortran.FortranScan("%sPATH" % dialect) + + for suffix in suffixes + ppsuffixes: + SCons.Tool.SourceFileScanner.add_scanner(suffix, fscan) + + env.AppendUnique(FORTRANSUFFIXES = suffixes + ppsuffixes) + + compaction, compppaction, shcompaction, shcompppaction = \ + CreateDialectActions(dialect) + + static_obj, shared_obj = SCons.Tool.createObjBuilders(env) + + for suffix in suffixes: + static_obj.add_action(suffix, compaction) + shared_obj.add_action(suffix, shcompaction) + static_obj.add_emitter(suffix, FortranEmitter) + shared_obj.add_emitter(suffix, ShFortranEmitter) + + for suffix in ppsuffixes: + static_obj.add_action(suffix, compppaction) + shared_obj.add_action(suffix, shcompppaction) + static_obj.add_emitter(suffix, FortranEmitter) + shared_obj.add_emitter(suffix, ShFortranEmitter) + + if '%sFLAGS' % dialect not in env: + env['%sFLAGS' % dialect] = SCons.Util.CLVar('') + + if 'SH%sFLAGS' % dialect not in env: + env['SH%sFLAGS' % dialect] = SCons.Util.CLVar('$%sFLAGS' % dialect) + + # If a tool does not define fortran prefix/suffix for include path, use C ones + if 'INC%sPREFIX' % dialect not in env: + env['INC%sPREFIX' % dialect] = '$INCPREFIX' + + if 'INC%sSUFFIX' % dialect not in env: + env['INC%sSUFFIX' % dialect] = '$INCSUFFIX' + + env['_%sINCFLAGS' % dialect] = '$( ${_concat(INC%sPREFIX, %sPATH, INC%sSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)' % (dialect, dialect, dialect) + + if support_module == 1: + env['%sCOM' % dialect] = '$%s -o $TARGET -c $%sFLAGS $_%sINCFLAGS $_FORTRANMODFLAG $SOURCES' % (dialect, dialect, dialect) + env['%sPPCOM' % dialect] = '$%s -o $TARGET -c $%sFLAGS $CPPFLAGS $_CPPDEFFLAGS $_%sINCFLAGS $_FORTRANMODFLAG $SOURCES' % (dialect, dialect, dialect) + env['SH%sCOM' % dialect] = '$SH%s -o $TARGET -c $SH%sFLAGS $_%sINCFLAGS $_FORTRANMODFLAG $SOURCES' % (dialect, dialect, dialect) + env['SH%sPPCOM' % dialect] = '$SH%s -o $TARGET -c $SH%sFLAGS $CPPFLAGS $_CPPDEFFLAGS $_%sINCFLAGS $_FORTRANMODFLAG $SOURCES' % (dialect, dialect, dialect) + else: + env['%sCOM' % dialect] = '$%s -o $TARGET -c $%sFLAGS $_%sINCFLAGS $SOURCES' % (dialect, dialect, dialect) + env['%sPPCOM' % dialect] = '$%s -o $TARGET -c $%sFLAGS $CPPFLAGS $_CPPDEFFLAGS $_%sINCFLAGS $SOURCES' % (dialect, dialect, dialect) + env['SH%sCOM' % dialect] = '$SH%s -o $TARGET -c $SH%sFLAGS $_%sINCFLAGS $SOURCES' % (dialect, dialect, dialect) + env['SH%sPPCOM' % dialect] = '$SH%s -o $TARGET -c $SH%sFLAGS $CPPFLAGS $_CPPDEFFLAGS $_%sINCFLAGS $SOURCES' % (dialect, dialect, dialect) + +def add_fortran_to_env(env): + """Add Builders and construction variables for Fortran to an Environment.""" + try: + FortranSuffixes = env['FORTRANFILESUFFIXES'] + except KeyError: + FortranSuffixes = ['.f', '.for', '.ftn'] + + #print("Adding %s to fortran suffixes" % FortranSuffixes) + try: + FortranPPSuffixes = env['FORTRANPPFILESUFFIXES'] + except KeyError: + FortranPPSuffixes = ['.fpp', '.FPP'] + + DialectAddToEnv(env, "FORTRAN", FortranSuffixes, + FortranPPSuffixes, support_module = 1) + + env['FORTRANMODPREFIX'] = '' # like $LIBPREFIX + env['FORTRANMODSUFFIX'] = '.mod' # like $LIBSUFFIX + + env['FORTRANMODDIR'] = '' # where the compiler should place .mod files + env['FORTRANMODDIRPREFIX'] = '' # some prefix to $FORTRANMODDIR - similar to $INCPREFIX + env['FORTRANMODDIRSUFFIX'] = '' # some suffix to $FORTRANMODDIR - similar to $INCSUFFIX + env['_FORTRANMODFLAG'] = '$( ${_concat(FORTRANMODDIRPREFIX, FORTRANMODDIR, FORTRANMODDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)' + +def add_f77_to_env(env): + """Add Builders and construction variables for f77 to an Environment.""" + try: + F77Suffixes = env['F77FILESUFFIXES'] + except KeyError: + F77Suffixes = ['.f77'] + + #print("Adding %s to f77 suffixes" % F77Suffixes) + try: + F77PPSuffixes = env['F77PPFILESUFFIXES'] + except KeyError: + F77PPSuffixes = [] + + DialectAddToEnv(env, "F77", F77Suffixes, F77PPSuffixes) + +def add_f90_to_env(env): + """Add Builders and construction variables for f90 to an Environment.""" + try: + F90Suffixes = env['F90FILESUFFIXES'] + except KeyError: + F90Suffixes = ['.f90'] + + #print("Adding %s to f90 suffixes" % F90Suffixes) + try: + F90PPSuffixes = env['F90PPFILESUFFIXES'] + except KeyError: + F90PPSuffixes = [] + + DialectAddToEnv(env, "F90", F90Suffixes, F90PPSuffixes, + support_module = 1) + +def add_f95_to_env(env): + """Add Builders and construction variables for f95 to an Environment.""" + try: + F95Suffixes = env['F95FILESUFFIXES'] + except KeyError: + F95Suffixes = ['.f95'] + + #print("Adding %s to f95 suffixes" % F95Suffixes) + try: + F95PPSuffixes = env['F95PPFILESUFFIXES'] + except KeyError: + F95PPSuffixes = [] + + DialectAddToEnv(env, "F95", F95Suffixes, F95PPSuffixes, + support_module = 1) + +def add_f03_to_env(env): + """Add Builders and construction variables for f03 to an Environment.""" + try: + F03Suffixes = env['F03FILESUFFIXES'] + except KeyError: + F03Suffixes = ['.f03'] + + #print("Adding %s to f95 suffixes" % F95Suffixes) + try: + F03PPSuffixes = env['F03PPFILESUFFIXES'] + except KeyError: + F03PPSuffixes = [] + + DialectAddToEnv(env, "F03", F03Suffixes, F03PPSuffixes, + support_module = 1) + +def add_f08_to_env(env): + """Add Builders and construction variables for f08 to an Environment.""" + try: + F08Suffixes = env['F08FILESUFFIXES'] + except KeyError: + F08Suffixes = ['.f08'] + + try: + F08PPSuffixes = env['F08PPFILESUFFIXES'] + except KeyError: + F08PPSuffixes = [] + + DialectAddToEnv(env, "F08", F08Suffixes, F08PPSuffixes, + support_module = 1) + +def add_all_to_env(env): + """Add builders and construction variables for all supported fortran + dialects.""" + add_fortran_to_env(env) + add_f77_to_env(env) + add_f90_to_env(env) + add_f95_to_env(env) + add_f03_to_env(env) + add_f08_to_env(env) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/GettextCommon.py b/tools/scons/scons-local-3.0.5/SCons/Tool/GettextCommon.py new file mode 100755 index 0000000000..37da33a938 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/GettextCommon.py @@ -0,0 +1,469 @@ +"""SCons.Tool.GettextCommon module + +Used by several tools of `gettext` toolset. +""" + +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +__revision__ = "src/engine/SCons/Tool/GettextCommon.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Warnings +import re + + +############################################################################# +class XgettextToolWarning(SCons.Warnings.Warning): pass + + +class XgettextNotFound(XgettextToolWarning): pass + + +class MsginitToolWarning(SCons.Warnings.Warning): pass + + +class MsginitNotFound(MsginitToolWarning): pass + + +class MsgmergeToolWarning(SCons.Warnings.Warning): pass + + +class MsgmergeNotFound(MsgmergeToolWarning): pass + + +class MsgfmtToolWarning(SCons.Warnings.Warning): pass + + +class MsgfmtNotFound(MsgfmtToolWarning): pass + + +############################################################################# +SCons.Warnings.enableWarningClass(XgettextToolWarning) +SCons.Warnings.enableWarningClass(XgettextNotFound) +SCons.Warnings.enableWarningClass(MsginitToolWarning) +SCons.Warnings.enableWarningClass(MsginitNotFound) +SCons.Warnings.enableWarningClass(MsgmergeToolWarning) +SCons.Warnings.enableWarningClass(MsgmergeNotFound) +SCons.Warnings.enableWarningClass(MsgfmtToolWarning) +SCons.Warnings.enableWarningClass(MsgfmtNotFound) + + +############################################################################# + +############################################################################# +class _POTargetFactory(object): + """ A factory of `PO` target files. + + Factory defaults differ from these of `SCons.Node.FS.FS`. We set `precious` + (this is required by builders and actions gettext) and `noclean` flags by + default for all produced nodes. + """ + + def __init__(self, env, nodefault=True, alias=None, precious=True + , noclean=True): + """ Object constructor. + + **Arguments** + + - *env* (`SCons.Environment.Environment`) + - *nodefault* (`boolean`) - if `True`, produced nodes will be ignored + from default target `'.'` + - *alias* (`string`) - if provided, produced nodes will be automatically + added to this alias, and alias will be set as `AlwaysBuild` + - *precious* (`boolean`) - if `True`, the produced nodes will be set as + `Precious`. + - *noclen* (`boolean`) - if `True`, the produced nodes will be excluded + from `Clean`. + """ + self.env = env + self.alias = alias + self.precious = precious + self.noclean = noclean + self.nodefault = nodefault + + def _create_node(self, name, factory, directory=None, create=1): + """ Create node, and set it up to factory settings. """ + import SCons.Util + node = factory(name, directory, create) + node.set_noclean(self.noclean) + node.set_precious(self.precious) + if self.nodefault: + self.env.Ignore('.', node) + if self.alias: + self.env.AlwaysBuild(self.env.Alias(self.alias, node)) + return node + + def Entry(self, name, directory=None, create=1): + """ Create `SCons.Node.FS.Entry` """ + return self._create_node(name, self.env.fs.Entry, directory, create) + + def File(self, name, directory=None, create=1): + """ Create `SCons.Node.FS.File` """ + return self._create_node(name, self.env.fs.File, directory, create) + + +############################################################################# + +############################################################################# +_re_comment = re.compile(r'(#[^\n\r]+)$', re.M) +_re_lang = re.compile(r'([a-zA-Z0-9_]+)', re.M) + + +############################################################################# +def _read_linguas_from_files(env, linguas_files=None): + """ Parse `LINGUAS` file and return list of extracted languages """ + import SCons.Util + import SCons.Environment + global _re_comment + global _re_lang + if not SCons.Util.is_List(linguas_files) \ + and not SCons.Util.is_String(linguas_files) \ + and not isinstance(linguas_files, SCons.Node.FS.Base) \ + and linguas_files: + # If, linguas_files==True or such, then read 'LINGUAS' file. + linguas_files = ['LINGUAS'] + if linguas_files is None: + return [] + fnodes = env.arg2nodes(linguas_files) + linguas = [] + for fnode in fnodes: + contents = _re_comment.sub("", fnode.get_text_contents()) + ls = [l for l in _re_lang.findall(contents) if l] + linguas.extend(ls) + return linguas + + +############################################################################# + +############################################################################# +from SCons.Builder import BuilderBase + + +############################################################################# +class _POFileBuilder(BuilderBase): + """ `PO` file builder. + + This is multi-target single-source builder. In typical situation the source + is single `POT` file, e.g. `messages.pot`, and there are multiple `PO` + targets to be updated from this `POT`. We must run + `SCons.Builder.BuilderBase._execute()` separatelly for each target to track + dependencies separatelly for each target file. + + **NOTE**: if we call `SCons.Builder.BuilderBase._execute(.., target, ...)` + with target being list of all targets, all targets would be rebuilt each time + one of the targets from this list is missing. This would happen, for example, + when new language `ll` enters `LINGUAS_FILE` (at this moment there is no + `ll.po` file yet). To avoid this, we override + `SCons.Builder.BuilerBase._execute()` and call it separatelly for each + target. Here we also append to the target list the languages read from + `LINGUAS_FILE`. + """ + + # + # * The argument for overriding _execute(): We must use environment with + # builder overrides applied (see BuilderBase.__init__(). Here it comes for + # free. + # * The argument against using 'emitter': The emitter is called too late + # by BuilderBase._execute(). If user calls, for example: + # + # env.POUpdate(LINGUAS_FILE = 'LINGUAS') + # + # the builder throws error, because it is called with target=None, + # source=None and is trying to "generate" sources or target list first. + # If user calls + # + # env.POUpdate(['foo', 'baz'], LINGUAS_FILE = 'LINGUAS') + # + # the env.BuilderWrapper() calls our builder with target=None, + # source=['foo', 'baz']. The BuilderBase._execute() then splits execution + # and execute iterativelly (recursion) self._execute(None, source[i]). + # After that it calls emitter (which is quite too late). The emitter is + # also called in each iteration, what makes things yet worse. + def __init__(self, env, **kw): + if not 'suffix' in kw: + kw['suffix'] = '$POSUFFIX' + if not 'src_suffix' in kw: + kw['src_suffix'] = '$POTSUFFIX' + if not 'src_builder' in kw: + kw['src_builder'] = '_POTUpdateBuilder' + if not 'single_source' in kw: + kw['single_source'] = True + alias = None + if 'target_alias' in kw: + alias = kw['target_alias'] + del kw['target_alias'] + if not 'target_factory' in kw: + kw['target_factory'] = _POTargetFactory(env, alias=alias).File + BuilderBase.__init__(self, **kw) + + def _execute(self, env, target, source, *args, **kw): + """ Execute builder's actions. + + Here we append to `target` the languages read from `$LINGUAS_FILE` and + apply `SCons.Builder.BuilderBase._execute()` separatelly to each target. + The arguments and return value are same as for + `SCons.Builder.BuilderBase._execute()`. + """ + import SCons.Util + import SCons.Node + linguas_files = None + if 'LINGUAS_FILE' in env and env['LINGUAS_FILE']: + linguas_files = env['LINGUAS_FILE'] + # This prevents endless recursion loop (we'll be invoked once for + # each target appended here, we must not extend the list again). + env['LINGUAS_FILE'] = None + linguas = _read_linguas_from_files(env, linguas_files) + if SCons.Util.is_List(target): + target.extend(linguas) + elif target is not None: + target = [target] + linguas + else: + target = linguas + if not target: + # Let the SCons.BuilderBase to handle this patologic situation + return BuilderBase._execute(self, env, target, source, *args, **kw) + # The rest is ours + if not SCons.Util.is_List(target): + target = [target] + result = [] + for tgt in target: + r = BuilderBase._execute(self, env, [tgt], source, *args, **kw) + result.extend(r) + if linguas_files is not None: + env['LINGUAS_FILE'] = linguas_files + return SCons.Node.NodeList(result) + + +############################################################################# + +import SCons.Environment + + +############################################################################# +def _translate(env, target=None, source=SCons.Environment._null, *args, **kw): + """ Function for `Translate()` pseudo-builder """ + if target is None: target = [] + pot = env.POTUpdate(None, source, *args, **kw) + po = env.POUpdate(target, pot, *args, **kw) + return po + + +############################################################################# + +############################################################################# +class RPaths(object): + """ Callable object, which returns pathnames relative to SCons current + working directory. + + It seems like `SCons.Node.FS.Base.get_path()` returns absolute paths + for nodes that are outside of current working directory (`env.fs.getcwd()`). + Here, we often have `SConscript`, `POT` and `PO` files within `po/` + directory and source files (e.g. `*.c`) outside of it. When generating `POT` + template file, references to source files are written to `POT` template, so + a translator may later quickly jump to appropriate source file and line from + its `PO` editor (e.g. `poedit`). Relative paths in `PO` file are usually + interpreted by `PO` editor as paths relative to the place, where `PO` file + lives. The absolute paths would make resultant `POT` file nonportable, as + the references would be correct only on the machine, where `POT` file was + recently re-created. For such reason, we need a function, which always + returns relative paths. This is the purpose of `RPaths` callable object. + + The `__call__` method returns paths relative to current working directory, but + we assume, that *xgettext(1)* is run from the directory, where target file is + going to be created. + + Note, that this may not work for files distributed over several hosts or + across different drives on windows. We assume here, that single local + filesystem holds both source files and target `POT` templates. + + Intended use of `RPaths` - in `xgettext.py`:: + + def generate(env): + from GettextCommon import RPaths + ... + sources = '$( ${_concat( "", SOURCES, "", __env__, XgettextRPaths, TARGET, SOURCES)} $)' + env.Append( + ... + XGETTEXTCOM = 'XGETTEXT ... ' + sources, + ... + XgettextRPaths = RPaths(env) + ) + """ + + # NOTE: This callable object returns pathnames of dirs/files relative to + # current working directory. The pathname remains relative also for entries + # that are outside of current working directory (node, that + # SCons.Node.FS.File and siblings return absolute path in such case). For + # simplicity we compute path relative to current working directory, this + # seems be enough for our purposes (don't need TARGET variable and + # SCons.Defaults.Variable_Caller stuff). + + def __init__(self, env): + """ Initialize `RPaths` callable object. + + **Arguments**: + + - *env* - a `SCons.Environment.Environment` object, defines *current + working dir*. + """ + self.env = env + + # FIXME: I'm not sure, how it should be implemented (what the *args are in + # general, what is **kw). + def __call__(self, nodes, *args, **kw): + """ Return nodes' paths (strings) relative to current working directory. + + **Arguments**: + + - *nodes* ([`SCons.Node.FS.Base`]) - list of nodes. + - *args* - currently unused. + - *kw* - currently unused. + + **Returns**: + + - Tuple of strings, which represent paths relative to current working + directory (for given environment). + """ + import os + import SCons.Node.FS + rpaths = () + cwd = self.env.fs.getcwd().get_abspath() + for node in nodes: + rpath = None + if isinstance(node, SCons.Node.FS.Base): + rpath = os.path.relpath(node.get_abspath(), cwd) + # FIXME: Other types possible here? + if rpath is not None: + rpaths += (rpath,) + return rpaths + + +############################################################################# + +############################################################################# +def _init_po_files(target, source, env): + """ Action function for `POInit` builder. """ + nop = lambda target, source, env: 0 + if 'POAUTOINIT' in env: + autoinit = env['POAUTOINIT'] + else: + autoinit = False + # Well, if everything outside works well, this loop should do single + # iteration. Otherwise we are rebuilding all the targets even, if just + # one has changed (but is this our fault?). + for tgt in target: + if not tgt.exists(): + if autoinit: + action = SCons.Action.Action('$MSGINITCOM', '$MSGINITCOMSTR') + else: + msg = 'File ' + repr(str(tgt)) + ' does not exist. ' \ + + 'If you are a translator, you can create it through: \n' \ + + '$MSGINITCOM' + action = SCons.Action.Action(nop, msg) + status = action([tgt], source, env) + if status: return status + return 0 + + +############################################################################# + +############################################################################# +def _detect_xgettext(env): + """ Detects *xgettext(1)* binary """ + if 'XGETTEXT' in env: + return env['XGETTEXT'] + xgettext = env.Detect('xgettext') + if xgettext: + return xgettext + raise SCons.Errors.StopError(XgettextNotFound, "Could not detect xgettext") + return None + + +############################################################################# +def _xgettext_exists(env): + return _detect_xgettext(env) + + +############################################################################# + +############################################################################# +def _detect_msginit(env): + """ Detects *msginit(1)* program. """ + if 'MSGINIT' in env: + return env['MSGINIT'] + msginit = env.Detect('msginit') + if msginit: + return msginit + raise SCons.Errors.StopError(MsginitNotFound, "Could not detect msginit") + return None + + +############################################################################# +def _msginit_exists(env): + return _detect_msginit(env) + + +############################################################################# + +############################################################################# +def _detect_msgmerge(env): + """ Detects *msgmerge(1)* program. """ + if 'MSGMERGE' in env: + return env['MSGMERGE'] + msgmerge = env.Detect('msgmerge') + if msgmerge: + return msgmerge + raise SCons.Errors.StopError(MsgmergeNotFound, "Could not detect msgmerge") + return None + + +############################################################################# +def _msgmerge_exists(env): + return _detect_msgmerge(env) + + +############################################################################# + +############################################################################# +def _detect_msgfmt(env): + """ Detects *msgmfmt(1)* program. """ + if 'MSGFMT' in env: + return env['MSGFMT'] + msgfmt = env.Detect('msgfmt') + if msgfmt: + return msgfmt + raise SCons.Errors.StopError(MsgfmtNotFound, "Could not detect msgfmt") + return None + + +############################################################################# +def _msgfmt_exists(env): + return _detect_msgfmt(env) + + +############################################################################# + +############################################################################# +def tool_list(platform, env): + """ List tools that shall be generated by top-level `gettext` tool """ + return ['xgettext', 'msginit', 'msgmerge', 'msgfmt'] + +############################################################################# diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/JavaCommon.py b/tools/scons/scons-local-3.0.5/SCons/Tool/JavaCommon.py new file mode 100755 index 0000000000..29ab007f55 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/JavaCommon.py @@ -0,0 +1,478 @@ +"""SCons.Tool.JavaCommon + +Stuff for processing Java. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/JavaCommon.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os +import os.path +import re +import glob + +java_parsing = 1 + +default_java_version = '1.4' + +# a switch for which jdk versions to use the Scope state for smarter +# anonymous inner class parsing. +scopeStateVersions = ('1.8') + +if java_parsing: + # Parse Java files for class names. + # + # This is a really cool parser from Charles Crain + # that finds appropriate class names in Java source. + + # A regular expression that will find, in a java file: + # newlines; + # double-backslashes; + # a single-line comment "//"; + # single or double quotes preceeded by a backslash; + # single quotes, double quotes, open or close braces, semi-colons, + # periods, open or close parentheses; + # floating-point numbers; + # any alphanumeric token (keyword, class name, specifier); + # any alphanumeric token surrounded by angle brackets (generics); + # the multi-line comment begin and end tokens /* and */; + # array declarations "[]". + _reToken = re.compile(r'(\n|\\\\|//|\\[\'"]|[\'"\{\}\;\.\(\)]|' + + r'\d*\.\d*|[A-Za-z_][\w\$\.]*|<[A-Za-z_]\w+>|' + + r'/\*|\*/|\[\])') + + class OuterState(object): + """The initial state for parsing a Java file for classes, + interfaces, and anonymous inner classes.""" + def __init__(self, version=default_java_version): + + if not version in ('1.1', '1.2', '1.3', '1.4', '1.5', '1.6', '1.7', + '1.8', '5', '6', '9.0', '10.0', '11.0'): + + msg = "Java version %s not supported" % version + raise NotImplementedError(msg) + + self.version = version + self.listClasses = [] + self.listOutputs = [] + self.stackBrackets = [] + self.brackets = 0 + self.nextAnon = 1 + self.localClasses = [] + self.stackAnonClassBrackets = [] + self.anonStacksStack = [[0]] + self.package = None + + def trace(self): + pass + + def __getClassState(self): + try: + return self.classState + except AttributeError: + ret = ClassState(self) + self.classState = ret + return ret + + def __getPackageState(self): + try: + return self.packageState + except AttributeError: + ret = PackageState(self) + self.packageState = ret + return ret + + def __getAnonClassState(self): + try: + return self.anonState + except AttributeError: + self.outer_state = self + ret = SkipState(1, AnonClassState(self)) + self.anonState = ret + return ret + + def __getSkipState(self): + try: + return self.skipState + except AttributeError: + ret = SkipState(1, self) + self.skipState = ret + return ret + + def _getAnonStack(self): + return self.anonStacksStack[-1] + + def openBracket(self): + self.brackets = self.brackets + 1 + + def closeBracket(self): + self.brackets = self.brackets - 1 + if len(self.stackBrackets) and \ + self.brackets == self.stackBrackets[-1]: + self.listOutputs.append('$'.join(self.listClasses)) + self.localClasses.pop() + self.listClasses.pop() + self.anonStacksStack.pop() + self.stackBrackets.pop() + if len(self.stackAnonClassBrackets) and \ + self.brackets == self.stackAnonClassBrackets[-1] and \ + self.version not in scopeStateVersions: + self._getAnonStack().pop() + self.stackAnonClassBrackets.pop() + + def parseToken(self, token): + if token[:2] == '//': + return IgnoreState('\n', self) + elif token == '/*': + return IgnoreState('*/', self) + elif token == '{': + self.openBracket() + elif token == '}': + self.closeBracket() + elif token in [ '"', "'" ]: + return IgnoreState(token, self) + elif token == "new": + # anonymous inner class + if len(self.listClasses) > 0: + return self.__getAnonClassState() + return self.__getSkipState() # Skip the class name + elif token in ['class', 'interface', 'enum']: + if len(self.listClasses) == 0: + self.nextAnon = 1 + self.stackBrackets.append(self.brackets) + return self.__getClassState() + elif token == 'package': + return self.__getPackageState() + elif token == '.': + # Skip the attribute, it might be named "class", in which + # case we don't want to treat the following token as + # an inner class name... + return self.__getSkipState() + return self + + def addAnonClass(self): + """Add an anonymous inner class""" + if self.version in ('1.1', '1.2', '1.3', '1.4'): + clazz = self.listClasses[0] + self.listOutputs.append('%s$%d' % (clazz, self.nextAnon)) + elif self.version in ('1.5', '1.6', '1.7', '1.8', '5', '6', '9.0', '10.0', '11.0'): + self.stackAnonClassBrackets.append(self.brackets) + className = [] + className.extend(self.listClasses) + self._getAnonStack()[-1] = self._getAnonStack()[-1] + 1 + for anon in self._getAnonStack(): + className.append(str(anon)) + self.listOutputs.append('$'.join(className)) + + self.nextAnon = self.nextAnon + 1 + self._getAnonStack().append(0) + + def setPackage(self, package): + self.package = package + + class ScopeState(object): + """ + A state that parses code within a scope normally, + within the confines of a scope. + """ + def __init__(self, old_state): + self.outer_state = old_state.outer_state + self.old_state = old_state + self.brackets = 0 + + def __getClassState(self): + try: + return self.classState + except AttributeError: + ret = ClassState(self) + self.classState = ret + return ret + + def __getAnonClassState(self): + try: + return self.anonState + except AttributeError: + ret = SkipState(1, AnonClassState(self)) + self.anonState = ret + return ret + + def __getSkipState(self): + try: + return self.skipState + except AttributeError: + ret = SkipState(1, self) + self.skipState = ret + return ret + + def openBracket(self): + self.brackets = self.brackets + 1 + + def closeBracket(self): + self.brackets = self.brackets - 1 + + def parseToken(self, token): + # if self.brackets == 0: + # return self.old_state.parseToken(token) + if token[:2] == '//': + return IgnoreState('\n', self) + elif token == '/*': + return IgnoreState('*/', self) + elif token == '{': + self.openBracket() + elif token == '}': + self.closeBracket() + if self.brackets == 0: + self.outer_state._getAnonStack().pop() + return self.old_state + elif token in ['"', "'"]: + return IgnoreState(token, self) + elif token == "new": + # anonymous inner class + return self.__getAnonClassState() + elif token == '.': + # Skip the attribute, it might be named "class", in which + # case we don't want to treat the following token as + # an inner class name... + return self.__getSkipState() + return self + + class AnonClassState(object): + """A state that looks for anonymous inner classes.""" + def __init__(self, old_state): + # outer_state is always an instance of OuterState + self.outer_state = old_state.outer_state + self.old_state = old_state + self.brace_level = 0 + def parseToken(self, token): + # This is an anonymous class if and only if the next + # non-whitespace token is a bracket. Everything between + # braces should be parsed as normal java code. + if token[:2] == '//': + return IgnoreState('\n', self) + elif token == '/*': + return IgnoreState('*/', self) + elif token == '\n': + return self + elif token[0] == '<' and token[-1] == '>': + return self + elif token == '(': + self.brace_level = self.brace_level + 1 + return self + if self.brace_level > 0: + if token == 'new': + # look further for anonymous inner class + return SkipState(1, AnonClassState(self)) + elif token in ['"', "'"]: + return IgnoreState(token, self) + elif token == ')': + self.brace_level = self.brace_level - 1 + return self + if token == '{': + self.outer_state.addAnonClass() + if self.outer_state.version in scopeStateVersions: + return ScopeState(old_state = self.old_state).parseToken(token) + return self.old_state.parseToken(token) + + class SkipState(object): + """A state that will skip a specified number of tokens before + reverting to the previous state.""" + def __init__(self, tokens_to_skip, old_state): + self.tokens_to_skip = tokens_to_skip + self.old_state = old_state + def parseToken(self, token): + self.tokens_to_skip = self.tokens_to_skip - 1 + if self.tokens_to_skip < 1: + return self.old_state + return self + + class ClassState(object): + """A state we go into when we hit a class or interface keyword.""" + def __init__(self, outer_state): + # outer_state is always an instance of OuterState + self.outer_state = outer_state + def parseToken(self, token): + # the next non-whitespace token should be the name of the class + if token == '\n': + return self + # If that's an inner class which is declared in a method, it + # requires an index prepended to the class-name, e.g. + # 'Foo$1Inner' + # https://github.com/SCons/scons/issues/2087 + if self.outer_state.localClasses and \ + self.outer_state.stackBrackets[-1] > \ + self.outer_state.stackBrackets[-2]+1: + locals = self.outer_state.localClasses[-1] + try: + idx = locals[token] + locals[token] = locals[token]+1 + except KeyError: + locals[token] = 1 + token = str(locals[token]) + token + self.outer_state.localClasses.append({}) + self.outer_state.listClasses.append(token) + self.outer_state.anonStacksStack.append([0]) + return self.outer_state + + class IgnoreState(object): + """A state that will ignore all tokens until it gets to a + specified token.""" + def __init__(self, ignore_until, old_state): + self.ignore_until = ignore_until + self.old_state = old_state + def parseToken(self, token): + if self.ignore_until == token: + return self.old_state + return self + + class PackageState(object): + """The state we enter when we encounter the package keyword. + We assume the next token will be the package name.""" + def __init__(self, outer_state): + # outer_state is always an instance of OuterState + self.outer_state = outer_state + def parseToken(self, token): + self.outer_state.setPackage(token) + return self.outer_state + + def parse_java_file(fn, version=default_java_version): + with open(fn, 'r') as f: + data = f.read() + return parse_java(data, version) + + def parse_java(contents, version=default_java_version, trace=None): + """Parse a .java file and return a double of package directory, + plus a list of .class files that compiling that .java file will + produce""" + package = None + initial = OuterState(version) + currstate = initial + for token in _reToken.findall(contents): + # The regex produces a bunch of groups, but only one will + # have anything in it. + currstate = currstate.parseToken(token) + if trace: trace(token, currstate) + if initial.package: + package = initial.package.replace('.', os.sep) + return (package, initial.listOutputs) + +else: + # Don't actually parse Java files for class names. + # + # We might make this a configurable option in the future if + # Java-file parsing takes too long (although it shouldn't relative + # to how long the Java compiler itself seems to take...). + + def parse_java_file(fn): + """ "Parse" a .java file. + + This actually just splits the file name, so the assumption here + is that the file name matches the public class name, and that + the path to the file is the same as the package name. + """ + return os.path.split(fn) + + + +java_win32_version_dir_glob = 'C:/Program Files*/Java/jdk%s*/bin' +java_win32_dir_glob = 'C:/Program Files*/Java/jdk*/bin' + +java_macos_include_dir = '/System/Library/Frameworks/JavaVM.framework/Headers/' +java_macos_version_include_dir = '/System/Library/Frameworks/JavaVM.framework/Versions/%s*/Headers/' + +java_linux_include_dirs = ['/usr/lib/jvm/default-java/include', + '/usr/lib/jvm/java-*/include'] +# Need to match path like below (from Centos 7) +# /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el7_5.x86_64/include/ +java_linux_version_include_dirs = ['/usr/lib/jvm/java-*-sun-%s*/include', + '/usr/lib/jvm/java-%s*-openjdk*/include', + '/usr/java/jdk%s*/include'] + + + +def get_java_install_dirs(platform, version=None): + """ + Using patterns above find the java jdk install dir + :param platform: + :param version: If specified, only look for java sdk's of this version + :return: list of default paths for java. + """ + paths = [] + if platform == 'win32': + if version: + paths = glob.glob(java_win32_version_dir_glob%version) + else: + paths = glob.glob(java_win32_dir_glob) + else: + # do nothing for now + pass + + paths=sorted(paths) + + return paths + +def get_java_include_paths(env, javac, version): + """ + Return java include paths + :param platform: + :param javac: + :return: + """ + paths = [] + if not javac: + # there are no paths if we've not detected javac. + pass + elif env['PLATFORM'] == 'win32': + javac_bin_dir = os.path.dirname(javac) + java_inc_dir = os.path.normpath(os.path.join(javac_bin_dir, '..', 'include')) + paths = [java_inc_dir, os.path.join(java_inc_dir, 'win32')] + elif env['PLATFORM'] == 'darwin': + if not version: + paths = [java_macos_include_dir] + else: + paths = sorted(glob.glob(java_macos_version_include_dir%version)) + else: + base_paths=[] + if not version: + for p in java_linux_include_dirs: + base_paths.extend(glob.glob(p)) + else: + for p in java_linux_version_include_dirs: + base_paths.extend(glob.glob(p%version)) + + for p in base_paths: + paths.extend([p, os.path.join(p,'linux')]) + + #print("PATHS:%s"%paths) + return paths + + + + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/MSCommon/__init__.py b/tools/scons/scons-local-3.0.5/SCons/Tool/MSCommon/__init__.py new file mode 100755 index 0000000000..2fb9c99eb1 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/MSCommon/__init__.py @@ -0,0 +1,57 @@ +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/MSCommon/__init__.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +__doc__ = """ +Common functions for Microsoft Visual Studio and Visual C/C++. +""" + +import copy +import os +import re +import subprocess + +import SCons.Errors +import SCons.Platform.win32 +import SCons.Util + +from SCons.Tool.MSCommon.sdk import mssdk_exists, \ + mssdk_setup_env + +from SCons.Tool.MSCommon.vc import msvc_exists, \ + msvc_setup_env, \ + msvc_setup_env_once, \ + msvc_version_to_maj_min + +from SCons.Tool.MSCommon.vs import get_default_version, \ + get_vs_by_version, \ + merge_default_version, \ + msvs_exists, \ + query_versions + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/MSCommon/arch.py b/tools/scons/scons-local-3.0.5/SCons/Tool/MSCommon/arch.py new file mode 100755 index 0000000000..12ff1f93e5 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/MSCommon/arch.py @@ -0,0 +1,67 @@ +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/MSCommon/arch.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +__doc__ = """Module to define supported Windows chip architectures. +""" + +import os + +class ArchDefinition(object): + """ + A class for defining architecture-specific settings and logic. + """ + def __init__(self, arch, synonyms=[]): + self.arch = arch + self.synonyms = synonyms + +SupportedArchitectureList = [ + ArchDefinition( + 'x86', + ['i386', 'i486', 'i586', 'i686'], + ), + + ArchDefinition( + 'x86_64', + ['AMD64', 'amd64', 'em64t', 'EM64T', 'x86_64'], + ), + + ArchDefinition( + 'ia64', + ['IA64'], + ), + + ArchDefinition( + 'arm', + ['ARM'], + ), + +] + +SupportedArchitectureMap = {} +for a in SupportedArchitectureList: + SupportedArchitectureMap[a.arch] = a + for s in a.synonyms: + SupportedArchitectureMap[s] = a + diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/MSCommon/common.py b/tools/scons/scons-local-3.0.5/SCons/Tool/MSCommon/common.py new file mode 100755 index 0000000000..041c394754 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/MSCommon/common.py @@ -0,0 +1,249 @@ +""" +Common helper functions for working with the Microsoft tool chain. +""" +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +from __future__ import print_function + +__revision__ = "src/engine/SCons/Tool/MSCommon/common.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import copy +import os +import subprocess +import re + +import SCons.Util + + +LOGFILE = os.environ.get('SCONS_MSCOMMON_DEBUG') +if LOGFILE == '-': + def debug(message): + print(message) +elif LOGFILE: + try: + import logging + except ImportError: + debug = lambda message: open(LOGFILE, 'a').write(message + '\n') + else: + logging.basicConfig(filename=LOGFILE, level=logging.DEBUG) + debug = logging.getLogger(name=__name__).debug +else: + debug = lambda x: None + + +_is_win64 = None + +def is_win64(): + """Return true if running on windows 64 bits. + + Works whether python itself runs in 64 bits or 32 bits.""" + # Unfortunately, python does not provide a useful way to determine + # if the underlying Windows OS is 32-bit or 64-bit. Worse, whether + # the Python itself is 32-bit or 64-bit affects what it returns, + # so nothing in sys.* or os.* help. + + # Apparently the best solution is to use env vars that Windows + # sets. If PROCESSOR_ARCHITECTURE is not x86, then the python + # process is running in 64 bit mode (on a 64-bit OS, 64-bit + # hardware, obviously). + # If this python is 32-bit but the OS is 64, Windows will set + # ProgramW6432 and PROCESSOR_ARCHITEW6432 to non-null. + # (Checking for HKLM\Software\Wow6432Node in the registry doesn't + # work, because some 32-bit installers create it.) + global _is_win64 + if _is_win64 is None: + # I structured these tests to make it easy to add new ones or + # add exceptions in the future, because this is a bit fragile. + _is_win64 = False + if os.environ.get('PROCESSOR_ARCHITECTURE', 'x86') != 'x86': + _is_win64 = True + if os.environ.get('PROCESSOR_ARCHITEW6432'): + _is_win64 = True + if os.environ.get('ProgramW6432'): + _is_win64 = True + return _is_win64 + + +def read_reg(value, hkroot=SCons.Util.HKEY_LOCAL_MACHINE): + return SCons.Util.RegGetValue(hkroot, value)[0] + +def has_reg(value): + """Return True if the given key exists in HKEY_LOCAL_MACHINE, False + otherwise.""" + try: + SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, value) + ret = True + except SCons.Util.WinError: + ret = False + return ret + +# Functions for fetching environment variable settings from batch files. + +def normalize_env(env, keys, force=False): + """Given a dictionary representing a shell environment, add the variables + from os.environ needed for the processing of .bat files; the keys are + controlled by the keys argument. + + It also makes sure the environment values are correctly encoded. + + If force=True, then all of the key values that exist are copied + into the returned dictionary. If force=false, values are only + copied if the key does not already exist in the copied dictionary. + + Note: the environment is copied.""" + normenv = {} + if env: + for k in list(env.keys()): + normenv[k] = copy.deepcopy(env[k]) + + for k in keys: + if k in os.environ and (force or not k in normenv): + normenv[k] = os.environ[k] + + # This shouldn't be necessary, since the default environment should include system32, + # but keep this here to be safe, since it's needed to find reg.exe which the MSVC + # bat scripts use. + sys32_dir = os.path.join(os.environ.get("SystemRoot", + os.environ.get("windir", r"C:\Windows\system32")), + "System32") + + if sys32_dir not in normenv['PATH']: + normenv['PATH'] = normenv['PATH'] + os.pathsep + sys32_dir + + # Without Wbem in PATH, vcvarsall.bat has a "'wmic' is not recognized" + # error starting with Visual Studio 2017, although the script still + # seems to work anyway. + sys32_wbem_dir = os.path.join(sys32_dir, 'Wbem') + if sys32_wbem_dir not in normenv['PATH']: + normenv['PATH'] = normenv['PATH'] + os.pathsep + sys32_wbem_dir + + debug("PATH: %s"%normenv['PATH']) + + return normenv + +def get_output(vcbat, args = None, env = None): + """Parse the output of given bat file, with given args.""" + + if env is None: + # Create a blank environment, for use in launching the tools + env = SCons.Environment.Environment(tools=[]) + + # TODO: This is a hard-coded list of the variables that (may) need + # to be imported from os.environ[] for v[sc]*vars*.bat file + # execution to work. This list should really be either directly + # controlled by vc.py, or else derived from the common_tools_var + # settings in vs.py. + vs_vc_vars = [ + 'COMSPEC', + # VS100 and VS110: Still set, but modern MSVC setup scripts will + # discard these if registry has values. However Intel compiler setup + # script still requires these as of 2013/2014. + 'VS140COMNTOOLS', + 'VS120COMNTOOLS', + 'VS110COMNTOOLS', + 'VS100COMNTOOLS', + 'VS90COMNTOOLS', + 'VS80COMNTOOLS', + 'VS71COMNTOOLS', + 'VS70COMNTOOLS', + 'VS60COMNTOOLS', + ] + env['ENV'] = normalize_env(env['ENV'], vs_vc_vars, force=False) + + if args: + debug("Calling '%s %s'" % (vcbat, args)) + popen = SCons.Action._subproc(env, + '"%s" %s & set' % (vcbat, args), + stdin='devnull', + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + else: + debug("Calling '%s'" % vcbat) + popen = SCons.Action._subproc(env, + '"%s" & set' % vcbat, + stdin='devnull', + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + + # Use the .stdout and .stderr attributes directly because the + # .communicate() method uses the threading module on Windows + # and won't work under Pythons not built with threading. + with popen.stdout: + stdout = popen.stdout.read() + with popen.stderr: + stderr = popen.stderr.read() + + # Extra debug logic, uncomment if necessary +# debug('get_output():stdout:%s'%stdout) +# debug('get_output():stderr:%s'%stderr) + + if stderr: + # TODO: find something better to do with stderr; + # this at least prevents errors from getting swallowed. + import sys + sys.stderr.write(stderr) + if popen.wait() != 0: + raise IOError(stderr.decode("mbcs")) + + output = stdout.decode("mbcs") + return output + +def parse_output(output, keep=("INCLUDE", "LIB", "LIBPATH", "PATH", 'VSCMD_ARG_app_plat')): + """ + Parse output from running visual c++/studios vcvarsall.bat and running set + To capture the values listed in keep + """ + + # dkeep is a dict associating key: path_list, where key is one item from + # keep, and pat_list the associated list of paths + dkeep = dict([(i, []) for i in keep]) + + # rdk will keep the regex to match the .bat file output line starts + rdk = {} + for i in keep: + rdk[i] = re.compile('%s=(.*)' % i, re.I) + + def add_env(rmatch, key, dkeep=dkeep): + path_list = rmatch.group(1).split(os.pathsep) + for path in path_list: + # Do not add empty paths (when a var ends with ;) + if path: + # XXX: For some reason, VC98 .bat file adds "" around the PATH + # values, and it screws up the environment later, so we strip + # it. + path = path.strip('"') + dkeep[key].append(str(path)) + + for line in output.splitlines(): + for k, value in rdk.items(): + match = value.match(line) + if match: + add_env(match, k) + + return dkeep + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/MSCommon/netframework.py b/tools/scons/scons-local-3.0.5/SCons/Tool/MSCommon/netframework.py new file mode 100755 index 0000000000..a32a05d347 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/MSCommon/netframework.py @@ -0,0 +1,83 @@ +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +__revision__ = "src/engine/SCons/Tool/MSCommon/netframework.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +__doc__ = """ +""" + +import os +import re +import SCons.Util + +from .common import read_reg, debug + +# Original value recorded by dcournapeau +_FRAMEWORKDIR_HKEY_ROOT = r'Software\Microsoft\.NETFramework\InstallRoot' +# On SGK's system +_FRAMEWORKDIR_HKEY_ROOT = r'Software\Microsoft\Microsoft SDKs\.NETFramework\v2.0\InstallationFolder' + +def find_framework_root(): + # XXX: find it from environment (FrameworkDir) + try: + froot = read_reg(_FRAMEWORKDIR_HKEY_ROOT) + debug("Found framework install root in registry: {}".format(froot)) + except SCons.Util.WinError as e: + debug("Could not read reg key {}".format(_FRAMEWORKDIR_HKEY_ROOT)) + return None + + if not os.path.exists(froot): + debug("{} not found on fs".format(froot)) + return None + + return froot + +def query_versions(): + froot = find_framework_root() + if froot: + contents = os.listdir(froot) + + l = re.compile('v[0-9]+.*') + versions = [e for e in contents if l.match(e)] + + def versrt(a,b): + # since version numbers aren't really floats... + aa = a[1:] + bb = b[1:] + aal = aa.split('.') + bbl = bb.split('.') + # sequence comparison in python is lexicographical + # which is exactly what we want. + # Note we sort backwards so the highest version is first. + return cmp(bbl,aal) + + versions.sort(versrt) + else: + versions = [] + + return versions + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/MSCommon/sdk.py b/tools/scons/scons-local-3.0.5/SCons/Tool/MSCommon/sdk.py new file mode 100755 index 0000000000..aa89f2a10d --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/MSCommon/sdk.py @@ -0,0 +1,413 @@ +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +__revision__ = "src/engine/SCons/Tool/MSCommon/sdk.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +__doc__ = """Module to detect the Platform/Windows SDK + +PSDK 2003 R1 is the earliest version detected. +""" + +import os + +import SCons.Errors +import SCons.Util + +from . import common + +debug = common.debug + +# SDK Checks. This is of course a mess as everything else on MS platforms. Here +# is what we do to detect the SDK: +# +# For Windows SDK >= 6.0: just look into the registry entries: +# HKLM\Software\Microsoft\Microsoft SDKs\Windows +# All the keys in there are the available versions. +# +# For Platform SDK before 6.0 (2003 server R1 and R2, etc...), there does not +# seem to be any sane registry key, so the precise location is hardcoded. +# +# For versions below 2003R1, it seems the PSDK is included with Visual Studio? +# +# Also, per the following: +# http://benjamin.smedbergs.us/blog/tag/atl/ +# VC++ Professional comes with the SDK, VC++ Express does not. + +# Location of the SDK (checked for 6.1 only) +_CURINSTALLED_SDK_HKEY_ROOT = \ + r"Software\Microsoft\Microsoft SDKs\Windows\CurrentInstallFolder" + + +class SDKDefinition(object): + """ + An abstract base class for trying to find installed SDK directories. + """ + def __init__(self, version, **kw): + self.version = version + self.__dict__.update(kw) + + def find_sdk_dir(self): + """Try to find the MS SDK from the registry. + + Return None if failed or the directory does not exist. + """ + if not SCons.Util.can_read_reg: + debug('find_sdk_dir(): can not read registry') + return None + + hkey = self.HKEY_FMT % self.hkey_data + debug('find_sdk_dir(): checking registry:{}'.format(hkey)) + + try: + sdk_dir = common.read_reg(hkey) + except SCons.Util.WinError as e: + debug('find_sdk_dir(): no SDK registry key {}'.format(repr(hkey))) + return None + + debug('find_sdk_dir(): Trying SDK Dir: {}'.format(sdk_dir)) + + if not os.path.exists(sdk_dir): + debug('find_sdk_dir(): {} not on file system'.format(sdk_dir)) + return None + + ftc = os.path.join(sdk_dir, self.sanity_check_file) + if not os.path.exists(ftc): + debug("find_sdk_dir(): sanity check {} not found".format(ftc)) + return None + + return sdk_dir + + def get_sdk_dir(self): + """Return the MSSSDK given the version string.""" + try: + return self._sdk_dir + except AttributeError: + sdk_dir = self.find_sdk_dir() + self._sdk_dir = sdk_dir + return sdk_dir + + def get_sdk_vc_script(self,host_arch, target_arch): + """ Return the script to initialize the VC compiler installed by SDK + """ + + if (host_arch == 'amd64' and target_arch == 'x86'): + # No cross tools needed compiling 32 bits on 64 bit machine + host_arch=target_arch + + arch_string=target_arch + if (host_arch != target_arch): + arch_string='%s_%s'%(host_arch,target_arch) + + debug("sdk.py: get_sdk_vc_script():arch_string:%s host_arch:%s target_arch:%s"%(arch_string, + host_arch, + target_arch)) + file=self.vc_setup_scripts.get(arch_string,None) + debug("sdk.py: get_sdk_vc_script():file:%s"%file) + return file + +class WindowsSDK(SDKDefinition): + """ + A subclass for trying to find installed Windows SDK directories. + """ + HKEY_FMT = r'Software\Microsoft\Microsoft SDKs\Windows\v%s\InstallationFolder' + def __init__(self, *args, **kw): + SDKDefinition.__init__(self, *args, **kw) + self.hkey_data = self.version + +class PlatformSDK(SDKDefinition): + """ + A subclass for trying to find installed Platform SDK directories. + """ + HKEY_FMT = r'Software\Microsoft\MicrosoftSDK\InstalledSDKS\%s\Install Dir' + def __init__(self, *args, **kw): + SDKDefinition.__init__(self, *args, **kw) + self.hkey_data = self.uuid + +# +# The list of VC initialization scripts installed by the SDK +# These should be tried if the vcvarsall.bat TARGET_ARCH fails +preSDK61VCSetupScripts = { 'x86' : r'bin\vcvars32.bat', + 'amd64' : r'bin\vcvarsamd64.bat', + 'x86_amd64': r'bin\vcvarsx86_amd64.bat', + 'x86_ia64' : r'bin\vcvarsx86_ia64.bat', + 'ia64' : r'bin\vcvarsia64.bat'} + +SDK61VCSetupScripts = {'x86' : r'bin\vcvars32.bat', + 'amd64' : r'bin\amd64\vcvarsamd64.bat', + 'x86_amd64': r'bin\x86_amd64\vcvarsx86_amd64.bat', + 'x86_ia64' : r'bin\x86_ia64\vcvarsx86_ia64.bat', + 'ia64' : r'bin\ia64\vcvarsia64.bat'} + +SDK70VCSetupScripts = { 'x86' : r'bin\vcvars32.bat', + 'amd64' : r'bin\vcvars64.bat', + 'x86_amd64': r'bin\vcvarsx86_amd64.bat', + 'x86_ia64' : r'bin\vcvarsx86_ia64.bat', + 'ia64' : r'bin\vcvarsia64.bat'} + +SDK100VCSetupScripts = {'x86' : r'bin\vcvars32.bat', + 'amd64' : r'bin\vcvars64.bat', + 'x86_amd64': r'bin\x86_amd64\vcvarsx86_amd64.bat', + 'x86_arm' : r'bin\x86_arm\vcvarsx86_arm.bat'} + + +# The list of support SDKs which we know how to detect. +# +# The first SDK found in the list is the one used by default if there +# are multiple SDKs installed. Barring good reasons to the contrary, +# this means we should list SDKs from most recent to oldest. +# +# If you update this list, update the documentation in Tool/mssdk.xml. +SupportedSDKList = [ + WindowsSDK('10.0A', + sanity_check_file=r'bin\SetEnv.Cmd', + include_subdir='include', + lib_subdir={ + 'x86' : ['lib'], + 'x86_64' : [r'lib\x64'], + 'ia64' : [r'lib\ia64'], + }, + vc_setup_scripts = SDK70VCSetupScripts, + ), + WindowsSDK('10.0', + sanity_check_file=r'bin\SetEnv.Cmd', + include_subdir='include', + lib_subdir={ + 'x86' : ['lib'], + 'x86_64' : [r'lib\x64'], + 'ia64' : [r'lib\ia64'], + }, + vc_setup_scripts = SDK70VCSetupScripts, + ), + WindowsSDK('7.1', + sanity_check_file=r'bin\SetEnv.Cmd', + include_subdir='include', + lib_subdir={ + 'x86' : ['lib'], + 'x86_64' : [r'lib\x64'], + 'ia64' : [r'lib\ia64'], + }, + vc_setup_scripts = SDK70VCSetupScripts, + ), + WindowsSDK('7.0A', + sanity_check_file=r'bin\SetEnv.Cmd', + include_subdir='include', + lib_subdir={ + 'x86' : ['lib'], + 'x86_64' : [r'lib\x64'], + 'ia64' : [r'lib\ia64'], + }, + vc_setup_scripts = SDK70VCSetupScripts, + ), + WindowsSDK('7.0', + sanity_check_file=r'bin\SetEnv.Cmd', + include_subdir='include', + lib_subdir={ + 'x86' : ['lib'], + 'x86_64' : [r'lib\x64'], + 'ia64' : [r'lib\ia64'], + }, + vc_setup_scripts = SDK70VCSetupScripts, + ), + WindowsSDK('6.1', + sanity_check_file=r'bin\SetEnv.Cmd', + include_subdir='include', + lib_subdir={ + 'x86' : ['lib'], + 'x86_64' : [r'lib\x64'], + 'ia64' : [r'lib\ia64'], + }, + vc_setup_scripts = SDK61VCSetupScripts, + ), + + WindowsSDK('6.0A', + sanity_check_file=r'include\windows.h', + include_subdir='include', + lib_subdir={ + 'x86' : ['lib'], + 'x86_64' : [r'lib\x64'], + 'ia64' : [r'lib\ia64'], + }, + vc_setup_scripts = preSDK61VCSetupScripts, + ), + + WindowsSDK('6.0', + sanity_check_file=r'bin\gacutil.exe', + include_subdir='include', + lib_subdir='lib', + vc_setup_scripts = preSDK61VCSetupScripts, + ), + + PlatformSDK('2003R2', + sanity_check_file=r'SetEnv.Cmd', + uuid="D2FF9F89-8AA2-4373-8A31-C838BF4DBBE1", + vc_setup_scripts = preSDK61VCSetupScripts, + ), + + PlatformSDK('2003R1', + sanity_check_file=r'SetEnv.Cmd', + uuid="8F9E5EF3-A9A5-491B-A889-C58EFFECE8B3", + vc_setup_scripts = preSDK61VCSetupScripts, + ), +] + +SupportedSDKMap = {} +for sdk in SupportedSDKList: + SupportedSDKMap[sdk.version] = sdk + + +# Finding installed SDKs isn't cheap, because it goes not only to the +# registry but also to the disk to sanity-check that there is, in fact, +# an SDK installed there and that the registry entry isn't just stale. +# Find this information once, when requested, and cache it. + +InstalledSDKList = None +InstalledSDKMap = None + +def get_installed_sdks(): + global InstalledSDKList + global InstalledSDKMap + debug('sdk.py:get_installed_sdks()') + if InstalledSDKList is None: + InstalledSDKList = [] + InstalledSDKMap = {} + for sdk in SupportedSDKList: + debug('MSCommon/sdk.py: trying to find SDK %s' % sdk.version) + if sdk.get_sdk_dir(): + debug('MSCommon/sdk.py:found SDK %s' % sdk.version) + InstalledSDKList.append(sdk) + InstalledSDKMap[sdk.version] = sdk + return InstalledSDKList + + +# We may be asked to update multiple construction environments with +# SDK information. When doing this, we check on-disk for whether +# the SDK has 'mfc' and 'atl' subdirectories. Since going to disk +# is expensive, cache results by directory. + +SDKEnvironmentUpdates = {} + +def set_sdk_by_directory(env, sdk_dir): + global SDKEnvironmentUpdates + debug('set_sdk_by_directory: Using dir:%s'%sdk_dir) + try: + env_tuple_list = SDKEnvironmentUpdates[sdk_dir] + except KeyError: + env_tuple_list = [] + SDKEnvironmentUpdates[sdk_dir] = env_tuple_list + + include_path = os.path.join(sdk_dir, 'include') + mfc_path = os.path.join(include_path, 'mfc') + atl_path = os.path.join(include_path, 'atl') + + if os.path.exists(mfc_path): + env_tuple_list.append(('INCLUDE', mfc_path)) + if os.path.exists(atl_path): + env_tuple_list.append(('INCLUDE', atl_path)) + env_tuple_list.append(('INCLUDE', include_path)) + + env_tuple_list.append(('LIB', os.path.join(sdk_dir, 'lib'))) + env_tuple_list.append(('LIBPATH', os.path.join(sdk_dir, 'lib'))) + env_tuple_list.append(('PATH', os.path.join(sdk_dir, 'bin'))) + + for variable, directory in env_tuple_list: + env.PrependENVPath(variable, directory) + +def get_sdk_by_version(mssdk): + if mssdk not in SupportedSDKMap: + raise SCons.Errors.UserError("SDK version {} is not supported".format(repr(mssdk))) + get_installed_sdks() + return InstalledSDKMap.get(mssdk) + +def get_default_sdk(): + """Set up the default Platform/Windows SDK.""" + get_installed_sdks() + if not InstalledSDKList: + return None + return InstalledSDKList[0] + +def mssdk_setup_env(env): + debug('sdk.py:mssdk_setup_env()') + if 'MSSDK_DIR' in env: + sdk_dir = env['MSSDK_DIR'] + if sdk_dir is None: + return + sdk_dir = env.subst(sdk_dir) + debug('sdk.py:mssdk_setup_env: Using MSSDK_DIR:{}'.format(sdk_dir)) + elif 'MSSDK_VERSION' in env: + sdk_version = env['MSSDK_VERSION'] + if sdk_version is None: + msg = "SDK version is specified as None" + raise SCons.Errors.UserError(msg) + sdk_version = env.subst(sdk_version) + mssdk = get_sdk_by_version(sdk_version) + if mssdk is None: + msg = "SDK version %s is not installed" % sdk_version + raise SCons.Errors.UserError(msg) + sdk_dir = mssdk.get_sdk_dir() + debug('sdk.py:mssdk_setup_env: Using MSSDK_VERSION:%s'%sdk_dir) + elif 'MSVS_VERSION' in env: + msvs_version = env['MSVS_VERSION'] + debug('sdk.py:mssdk_setup_env:Getting MSVS_VERSION from env:%s'%msvs_version) + if msvs_version is None: + debug('sdk.py:mssdk_setup_env thinks msvs_version is None') + return + msvs_version = env.subst(msvs_version) + from . import vs + msvs = vs.get_vs_by_version(msvs_version) + debug('sdk.py:mssdk_setup_env:msvs is :%s'%msvs) + if not msvs: + debug('sdk.py:mssdk_setup_env: no VS version detected, bailingout:%s'%msvs) + return + sdk_version = msvs.sdk_version + debug('sdk.py:msvs.sdk_version is %s'%sdk_version) + if not sdk_version: + return + mssdk = get_sdk_by_version(sdk_version) + if not mssdk: + mssdk = get_default_sdk() + if not mssdk: + return + sdk_dir = mssdk.get_sdk_dir() + debug('sdk.py:mssdk_setup_env: Using MSVS_VERSION:%s'%sdk_dir) + else: + mssdk = get_default_sdk() + if not mssdk: + return + sdk_dir = mssdk.get_sdk_dir() + debug('sdk.py:mssdk_setup_env: not using any env values. sdk_dir:%s'%sdk_dir) + + set_sdk_by_directory(env, sdk_dir) + + #print "No MSVS_VERSION: this is likely to be a bug" + +def mssdk_exists(version=None): + sdks = get_installed_sdks() + if version is None: + return len(sdks) > 0 + return version in sdks + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/MSCommon/vc.py b/tools/scons/scons-local-3.0.5/SCons/Tool/MSCommon/vc.py new file mode 100755 index 0000000000..1f1332ef96 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/MSCommon/vc.py @@ -0,0 +1,775 @@ +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +# TODO: +# * supported arch for versions: for old versions of batch file without +# argument, giving bogus argument cannot be detected, so we have to hardcode +# this here +# * print warning when msvc version specified but not found +# * find out why warning do not print +# * test on 64 bits XP + VS 2005 (and VS 6 if possible) +# * SDK +# * Assembly +__revision__ = "src/engine/SCons/Tool/MSCommon/vc.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +__doc__ = """Module for Visual C/C++ detection and configuration. +""" +import SCons.compat +import SCons.Util + +import subprocess +import os +import platform +from string import digits as string_digits + +import SCons.Warnings +from SCons.Tool import find_program_path + +from . import common + +debug = common.debug + +from . import sdk + +get_installed_sdks = sdk.get_installed_sdks + + +class VisualCException(Exception): + pass + +class UnsupportedVersion(VisualCException): + pass + +class UnsupportedArch(VisualCException): + pass + +class MissingConfiguration(VisualCException): + pass + +class NoVersionFound(VisualCException): + pass + +class BatchFileExecutionError(VisualCException): + pass + +# Dict to 'canonalize' the arch +_ARCH_TO_CANONICAL = { + "amd64" : "amd64", + "emt64" : "amd64", + "i386" : "x86", + "i486" : "x86", + "i586" : "x86", + "i686" : "x86", + "ia64" : "ia64", # deprecated + "itanium" : "ia64", # deprecated + "x86" : "x86", + "x86_64" : "amd64", + "arm" : "arm", + "arm64" : "arm64", + "aarch64" : "arm64", +} + +# get path to the cl.exe dir for newer VS versions +# based off a tuple of (host, target) platforms +_HOST_TARGET_TO_CL_DIR_GREATER_THAN_14 = { + ("amd64","amd64") : "Hostx64\\x64", + ("amd64","x86") : "Hostx64\\x86", + ("amd64","arm") : "Hostx64\\arm", + ("amd64","arm64") : "Hostx64\\arm64", + ("x86","amd64") : "Hostx86\\x64", + ("x86","x86") : "Hostx86\\x86", + ("x86","arm") : "Hostx86\\arm", + ("x86","arm64") : "Hostx86\\arm64", +} + +# get path to the cl.exe dir for older VS versions +# based off a tuple of (host, target) platforms +_HOST_TARGET_TO_CL_DIR = { + ("amd64","amd64") : "amd64", + ("amd64","x86") : "amd64_x86", + ("amd64","arm") : "amd64_arm", + ("amd64","arm64") : "amd64_arm64", + ("x86","amd64") : "x86_amd64", + ("x86","x86") : "", + ("x86","arm") : "x86_arm", + ("x86","arm64") : "x86_arm64", +} + +# Given a (host, target) tuple, return the argument for the bat file. +# Both host and targets should be canonalized. +_HOST_TARGET_ARCH_TO_BAT_ARCH = { + ("x86", "x86"): "x86", + ("x86", "amd64"): "x86_amd64", + ("x86", "x86_amd64"): "x86_amd64", + ("amd64", "x86_amd64"): "x86_amd64", # This is present in (at least) VS2012 express + ("amd64", "amd64"): "amd64", + ("amd64", "x86"): "x86", + ("x86", "ia64"): "x86_ia64", # gone since 14.0 + ("arm", "arm"): "arm", # since 14.0, maybe gone 14.1? + ("x86", "arm"): "x86_arm", # since 14.0 + ("x86", "arm64"): "x86_arm64", # since 14.1 + ("amd64", "arm"): "amd64_arm", # since 14.0 + ("amd64", "arm64"): "amd64_arm64", # since 14.1 +} + +_CL_EXE_NAME = 'cl.exe' + +def get_msvc_version_numeric(msvc_version): + """Get the raw version numbers from a MSVC_VERSION string, so it + could be cast to float or other numeric values. For example, '14.0Exp' + would get converted to '14.0'. + + Args: + msvc_version: str + string representing the version number, could contain non + digit characters + + Returns: + str: the value converted to a numeric only string + + """ + return ''.join([x for x in msvc_version if x in string_digits + '.']) + +def get_host_target(env): + debug('vc.py:get_host_target()') + + host_platform = env.get('HOST_ARCH') + if not host_platform: + host_platform = platform.machine() + # TODO(2.5): the native Python platform.machine() function returns + # '' on all Python versions before 2.6, after which it also uses + # PROCESSOR_ARCHITECTURE. + if not host_platform: + host_platform = os.environ.get('PROCESSOR_ARCHITECTURE', '') + + # Retain user requested TARGET_ARCH + req_target_platform = env.get('TARGET_ARCH') + debug('vc.py:get_host_target() req_target_platform:%s'%req_target_platform) + + if req_target_platform: + # If user requested a specific platform then only try that one. + target_platform = req_target_platform + else: + target_platform = host_platform + + try: + host = _ARCH_TO_CANONICAL[host_platform.lower()] + except KeyError as e: + msg = "Unrecognized host architecture %s" + raise ValueError(msg % repr(host_platform)) + + try: + target = _ARCH_TO_CANONICAL[target_platform.lower()] + except KeyError as e: + all_archs = str(list(_ARCH_TO_CANONICAL.keys())) + raise ValueError("Unrecognized target architecture %s\n\tValid architectures: %s" % (target_platform, all_archs)) + + return (host, target,req_target_platform) + +# If you update this, update SupportedVSList in Tool/MSCommon/vs.py, and the +# MSVC_VERSION documentation in Tool/msvc.xml. +_VCVER = ["14.1", "14.0", "14.0Exp", "12.0", "12.0Exp", "11.0", "11.0Exp", "10.0", "10.0Exp", "9.0", "9.0Exp","8.0", "8.0Exp","7.1", "7.0", "6.0"] + +_VCVER_TO_PRODUCT_DIR = { + '14.1' : [ + (SCons.Util.HKEY_LOCAL_MACHINE, r'')], # Visual Studio 2017 doesn't set this registry key anymore + '14.0' : [ + (SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\14.0\Setup\VC\ProductDir')], + '14.0Exp' : [ + (SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VCExpress\14.0\Setup\VC\ProductDir')], + '12.0' : [ + (SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\12.0\Setup\VC\ProductDir'), + ], + '12.0Exp' : [ + (SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VCExpress\12.0\Setup\VC\ProductDir'), + ], + '11.0': [ + (SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\11.0\Setup\VC\ProductDir'), + ], + '11.0Exp' : [ + (SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VCExpress\11.0\Setup\VC\ProductDir'), + ], + '10.0': [ + (SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\10.0\Setup\VC\ProductDir'), + ], + '10.0Exp' : [ + (SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VCExpress\10.0\Setup\VC\ProductDir'), + ], + '9.0': [ + (SCons.Util.HKEY_CURRENT_USER, r'Microsoft\DevDiv\VCForPython\9.0\installdir',), + (SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\9.0\Setup\VC\ProductDir',), + ], + '9.0Exp' : [ + (SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VCExpress\9.0\Setup\VC\ProductDir'), + ], + '8.0': [ + (SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\8.0\Setup\VC\ProductDir'), + ], + '8.0Exp': [ + (SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VCExpress\8.0\Setup\VC\ProductDir'), + ], + '7.1': [ + (SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\7.1\Setup\VC\ProductDir'), + ], + '7.0': [ + (SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\7.0\Setup\VC\ProductDir'), + ], + '6.0': [ + (SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\6.0\Setup\Microsoft Visual C++\ProductDir'), + ] +} + +def msvc_version_to_maj_min(msvc_version): + msvc_version_numeric = get_msvc_version_numeric(msvc_version) + + t = msvc_version_numeric.split(".") + if not len(t) == 2: + raise ValueError("Unrecognized version %s (%s)" % (msvc_version,msvc_version_numeric)) + try: + maj = int(t[0]) + min = int(t[1]) + return maj, min + except ValueError as e: + raise ValueError("Unrecognized version %s (%s)" % (msvc_version,msvc_version_numeric)) + +def is_host_target_supported(host_target, msvc_version): + """Check if the given (host, target) tuple is supported for given version. + + Args: + host_target: tuple + tuple of (canonalized) host-targets, e.g. ("x86", "amd64") + for cross compilation from 32 bit Windows to 64 bits. + msvc_version: str + msvc version (major.minor, e.g. 10.0) + + Returns: + bool: + + Note: + This only checks whether a given version *may* support the given (host, + target), not that the toolchain is actually present on the machine. + """ + # We assume that any Visual Studio version supports x86 as a target + if host_target[1] != "x86": + maj, min = msvc_version_to_maj_min(msvc_version) + if maj < 8: + return False + + return True + + +def find_vc_pdir_vswhere(msvc_version): + """ + Find the MSVC product directory using vswhere.exe. + + Run it asking for specified version and get MSVS install location + :param msvc_version: + :return: MSVC install dir or None + """ + + # For bug 3333 - support default location of vswhere for both 64 and 32 bit windows + # installs. + for pf in ['Program Files (x86)', 'Program Files']: + vswhere_path = os.path.join( + 'C:\\', + pf, + 'Microsoft Visual Studio', + 'Installer', + 'vswhere.exe' + ) + if os.path.exists(vswhere_path): + # If we found vswhere, then use it. + break + + vswhere_cmd = [vswhere_path, '-products', '*', '-version', msvc_version, '-property', 'installationPath'] + + if os.path.exists(vswhere_path): + #TODO PY27 cannot use Popen as context manager + # try putting it back to the old way for now + sp = subprocess.Popen(vswhere_cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + vsdir, err = sp.communicate() + if vsdir: + vsdir = vsdir.decode("mbcs").splitlines() + # vswhere could easily return multiple lines + # we could define a way to pick the one we prefer, but since + # this data is currently only used to make a check for existence, + # returning the first hit should be good enough for now. + vc_pdir = os.path.join(vsdir[0], 'VC') + return vc_pdir + else: + # No vswhere on system, no install info available + return None + + +def find_vc_pdir(msvc_version): + """Find the product directory for the given version. + + Tries to look up the path using a registry key from the table + _VCVER_TO_PRODUCT_DIR; if there is no key, calls find_vc_pdir_wshere + for help instead. + + Args: + msvc_version: str + msvc version (major.minor, e.g. 10.0) + + Returns: + str: Path found in registry, or None + + Raises: + UnsupportedVersion: if the version is not known by this file. + MissingConfiguration: found version but the directory is missing. + + Both exceptions inherit from VisualCException. + """ + root = 'Software\\' + try: + hkeys = _VCVER_TO_PRODUCT_DIR[msvc_version] + except KeyError: + debug("Unknown version of MSVC: %s" % msvc_version) + raise UnsupportedVersion("Unknown version %s" % msvc_version) + + for hkroot, key in hkeys: + try: + comps = None + if not key: + comps = find_vc_pdir_vswhere(msvc_version) + if not comps: + debug('find_vc_pdir_vswhere(): no VC found for version {}'.format(repr(msvc_version))) + raise SCons.Util.WinError + debug('find_vc_pdir_vswhere(): VC found: {}'.format(repr(msvc_version))) + return comps + else: + if common.is_win64(): + try: + # ordinally at win64, try Wow6432Node first. + comps = common.read_reg(root + 'Wow6432Node\\' + key, hkroot) + except SCons.Util.WinError as e: + # at Microsoft Visual Studio for Python 2.7, value is not in Wow6432Node + pass + if not comps: + # not Win64, or Microsoft Visual Studio for Python 2.7 + comps = common.read_reg(root + key, hkroot) + except SCons.Util.WinError as e: + debug('find_vc_dir(): no VC registry key {}'.format(repr(key))) + else: + debug('find_vc_dir(): found VC in registry: {}'.format(comps)) + if os.path.exists(comps): + return comps + else: + debug('find_vc_dir(): reg says dir is {}, but it does not exist. (ignoring)'.format(comps)) + raise MissingConfiguration("registry dir {} not found on the filesystem".format(comps)) + return None + +def find_batch_file(env,msvc_version,host_arch,target_arch): + """ + Find the location of the batch script which should set up the compiler + for any TARGET_ARCH whose compilers were installed by Visual Studio/VCExpress + """ + pdir = find_vc_pdir(msvc_version) + if pdir is None: + raise NoVersionFound("No version of Visual Studio found") + + debug('vc.py: find_batch_file() in {}'.format(pdir)) + + # filter out e.g. "Exp" from the version name + msvc_ver_numeric = get_msvc_version_numeric(msvc_version) + vernum = float(msvc_ver_numeric) + if 7 <= vernum < 8: + pdir = os.path.join(pdir, os.pardir, "Common7", "Tools") + batfilename = os.path.join(pdir, "vsvars32.bat") + elif vernum < 7: + pdir = os.path.join(pdir, "Bin") + batfilename = os.path.join(pdir, "vcvars32.bat") + elif 8 <= vernum <= 14: + batfilename = os.path.join(pdir, "vcvarsall.bat") + else: # vernum >= 14.1 VS2017 and above + batfilename = os.path.join(pdir, "Auxiliary", "Build", "vcvarsall.bat") + + if not os.path.exists(batfilename): + debug("Not found: %s" % batfilename) + batfilename = None + + installed_sdks=get_installed_sdks() + for _sdk in installed_sdks: + sdk_bat_file = _sdk.get_sdk_vc_script(host_arch,target_arch) + if not sdk_bat_file: + debug("vc.py:find_batch_file() not found:%s"%_sdk) + else: + sdk_bat_file_path = os.path.join(pdir,sdk_bat_file) + if os.path.exists(sdk_bat_file_path): + debug('vc.py:find_batch_file() sdk_bat_file_path:%s'%sdk_bat_file_path) + return (batfilename,sdk_bat_file_path) + return (batfilename,None) + + +__INSTALLED_VCS_RUN = None + +def _check_cl_exists_in_vc_dir(env, vc_dir, msvc_version): + """Find the cl.exe on the filesystem in the vc_dir depending on + TARGET_ARCH, HOST_ARCH and the msvc version. TARGET_ARCH and + HOST_ARCH can be extracted from the passed env, unless its None, + which then the native platform is assumed the host and target. + + Args: + env: Environment + a construction environment, usually if this is passed its + because there is a desired TARGET_ARCH to be used when searching + for a cl.exe + vc_dir: str + the path to the VC dir in the MSVC installation + msvc_version: str + msvc version (major.minor, e.g. 10.0) + + Returns: + bool: + + """ + + # determine if there is a specific target platform we want to build for and + # use that to find a list of valid VCs, default is host platform == target platform + # and same for if no env is specified to extract target platform from + if env: + (host_platform, target_platform, req_target_platform) = get_host_target(env) + else: + host_platform = platform.machine().lower() + target_platform = host_platform + + host_platform = _ARCH_TO_CANONICAL[host_platform] + target_platform = _ARCH_TO_CANONICAL[target_platform] + + debug('_check_cl_exists_in_vc_dir(): host platform %s, target platform %s' % (host_platform, target_platform)) + + ver_num = float(get_msvc_version_numeric(msvc_version)) + + # make sure the cl.exe exists meaning the tool is installed + if ver_num > 14: + # 2017 and newer allowed multiple versions of the VC toolset to be installed at the same time. + # Just get the default tool version for now + #TODO: support setting a specific minor VC version + default_toolset_file = os.path.join(vc_dir, r'Auxiliary\Build\Microsoft.VCToolsVersion.default.txt') + try: + with open(default_toolset_file) as f: + vc_specific_version = f.readlines()[0].strip() + except IOError: + debug('_check_cl_exists_in_vc_dir(): failed to read ' + default_toolset_file) + return False + except IndexError: + debug('_check_cl_exists_in_vc_dir(): failed to find MSVC version in ' + default_toolset_file) + return False + + host_trgt_dir = _HOST_TARGET_TO_CL_DIR_GREATER_THAN_14.get((host_platform, target_platform), None) + if not host_trgt_dir: + debug('_check_cl_exists_in_vc_dir(): unsupported host/target platform combo') + return False + + cl_path = os.path.join(vc_dir, r'Tools\MSVC', vc_specific_version, 'bin', host_trgt_dir, _CL_EXE_NAME) + debug('_check_cl_exists_in_vc_dir(): checking for ' + _CL_EXE_NAME + ' at ' + cl_path) + if os.path.exists(cl_path): + debug('_check_cl_exists_in_vc_dir(): found ' + _CL_EXE_NAME + '!') + return True + + elif ver_num <= 14 and ver_num >= 8: + + host_trgt_dir = _HOST_TARGET_TO_CL_DIR.get((host_platform, target_platform), None) + if not host_trgt_dir: + debug('_check_cl_exists_in_vc_dir(): unsupported host/target platform combo') + return False + + cl_path = os.path.join(vc_dir, 'bin', host_trgt_dir, _CL_EXE_NAME) + debug('_check_cl_exists_in_vc_dir(): checking for ' + _CL_EXE_NAME + ' at ' + cl_path) + + cl_path_exists = os.path.exists(cl_path) + if not cl_path_exists and host_platform == 'amd64': + # older versions of visual studio only had x86 binaries, + # so if the host platform is amd64, we need to check cross + # compile options (x86 binary compiles some other target on a 64 bit os) + host_trgt_dir = _HOST_TARGET_TO_CL_DIR.get(('x86', target_platform), None) + if not host_trgt_dir: + return False + + cl_path = os.path.join(vc_dir, 'bin', host_trgt_dir, _CL_EXE_NAME) + debug('_check_cl_exists_in_vc_dir(): checking for ' + _CL_EXE_NAME + ' at ' + cl_path) + cl_path_exists = os.path.exists(cl_path) + + if cl_path_exists: + debug('_check_cl_exists_in_vc_dir(): found ' + _CL_EXE_NAME + '!') + return True + + elif ver_num < 8 and ver_num >= 6: + # not sure about these versions so if a walk the VC dir (could be slow) + for root, _, files in os.walk(vc_dir): + if _CL_EXE_NAME in files: + debug('get_installed_vcs ' + _CL_EXE_NAME + ' found %s' % os.path.join(root, _CL_EXE_NAME)) + return True + return False + else: + # version not support return false + debug('_check_cl_exists_in_vc_dir(): unsupported MSVC version: ' + str(ver_num)) + + return False + +def cached_get_installed_vcs(env=None): + global __INSTALLED_VCS_RUN + + if __INSTALLED_VCS_RUN is None: + ret = get_installed_vcs(env) + __INSTALLED_VCS_RUN = ret + + return __INSTALLED_VCS_RUN + +def get_installed_vcs(env=None): + installed_versions = [] + + for ver in _VCVER: + debug('trying to find VC %s' % ver) + try: + VC_DIR = find_vc_pdir(ver) + if VC_DIR: + debug('found VC %s' % ver) + if _check_cl_exists_in_vc_dir(env, VC_DIR, ver): + installed_versions.append(ver) + else: + debug('find_vc_pdir no compiler found %s' % ver) + else: + debug('find_vc_pdir return None for ver %s' % ver) + except VisualCException as e: + debug('did not find VC %s: caught exception %s' % (ver, str(e))) + return installed_versions + +def reset_installed_vcs(): + """Make it try again to find VC. This is just for the tests.""" + __INSTALLED_VCS_RUN = None + +# Running these batch files isn't cheap: most of the time spent in +# msvs.generate() is due to vcvars*.bat. In a build that uses "tools='msvs'" +# in multiple environments, for example: +# env1 = Environment(tools='msvs') +# env2 = Environment(tools='msvs') +# we can greatly improve the speed of the second and subsequent Environment +# (or Clone) calls by memoizing the environment variables set by vcvars*.bat. +script_env_stdout_cache = {} +def script_env(script, args=None): + cache_key = (script, args) + stdout = script_env_stdout_cache.get(cache_key, None) + if stdout is None: + stdout = common.get_output(script, args) + script_env_stdout_cache[cache_key] = stdout + + # Stupid batch files do not set return code: we take a look at the + # beginning of the output for an error message instead + olines = stdout.splitlines() + if olines[0].startswith("The specified configuration type is missing"): + raise BatchFileExecutionError("\n".join(olines[:2])) + + return common.parse_output(stdout) + +def get_default_version(env): + debug('get_default_version()') + + msvc_version = env.get('MSVC_VERSION') + msvs_version = env.get('MSVS_VERSION') + + debug('get_default_version(): msvc_version:%s msvs_version:%s'%(msvc_version,msvs_version)) + + if msvs_version and not msvc_version: + SCons.Warnings.warn( + SCons.Warnings.DeprecatedWarning, + "MSVS_VERSION is deprecated: please use MSVC_VERSION instead ") + return msvs_version + elif msvc_version and msvs_version: + if not msvc_version == msvs_version: + SCons.Warnings.warn( + SCons.Warnings.VisualVersionMismatch, + "Requested msvc version (%s) and msvs version (%s) do " \ + "not match: please use MSVC_VERSION only to request a " \ + "visual studio version, MSVS_VERSION is deprecated" \ + % (msvc_version, msvs_version)) + return msvs_version + if not msvc_version: + installed_vcs = cached_get_installed_vcs(env) + debug('installed_vcs:%s' % installed_vcs) + if not installed_vcs: + #msg = 'No installed VCs' + #debug('msv %s\n' % repr(msg)) + #SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, msg) + debug('msvc_setup_env: No installed VCs') + return None + msvc_version = installed_vcs[0] + debug('msvc_setup_env: using default installed MSVC version %s\n' % repr(msvc_version)) + + return msvc_version + +def msvc_setup_env_once(env): + try: + has_run = env["MSVC_SETUP_RUN"] + except KeyError: + has_run = False + + if not has_run: + msvc_setup_env(env) + env["MSVC_SETUP_RUN"] = True + +def msvc_find_valid_batch_script(env,version): + debug('vc.py:msvc_find_valid_batch_script()') + # Find the host platform, target platform, and if present the requested + # target platform + platforms = get_host_target(env) + debug("vc.py: msvs_find_valid_batch_script(): host_platform %s, target_platform %s req_target_platform:%s" % platforms) + + host_platform, target_platform, req_target_platform = platforms + try_target_archs = [target_platform] + + # VS2012 has a "cross compile" environment to build 64 bit + # with x86_amd64 as the argument to the batch setup script + if req_target_platform in ('amd64', 'x86_64'): + try_target_archs.append('x86_amd64') + elif not req_target_platform and target_platform in ['amd64', 'x86_64']: + # There may not be "native" amd64, but maybe "cross" x86_amd64 tools + try_target_archs.append('x86_amd64') + # If the user hasn't specifically requested a TARGET_ARCH, and + # The TARGET_ARCH is amd64 then also try 32 bits if there are no viable + # 64 bit tools installed + try_target_archs.append('x86') + + debug("msvs_find_valid_batch_script(): host_platform: %s try_target_archs:%s"%(host_platform, try_target_archs)) + + d = None + for tp in try_target_archs: + # Set to current arch. + env['TARGET_ARCH']=tp + + debug("vc.py:msvc_find_valid_batch_script() trying target_platform:%s"%tp) + host_target = (host_platform, tp) + if not is_host_target_supported(host_target, version): + warn_msg = "host, target = %s not supported for MSVC version %s" % \ + (host_target, version) + SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg) + arg = _HOST_TARGET_ARCH_TO_BAT_ARCH[host_target] + + # Get just version numbers + maj, min = msvc_version_to_maj_min(version) + # VS2015+ + if maj >= 14: + if env.get('MSVC_UWP_APP') == '1': + # Initialize environment variables with store/universal paths + arg += ' store' + + # Try to locate a batch file for this host/target platform combo + try: + (vc_script,sdk_script) = find_batch_file(env,version,host_platform,tp) + debug('vc.py:msvc_find_valid_batch_script() vc_script:%s sdk_script:%s'%(vc_script,sdk_script)) + except VisualCException as e: + msg = str(e) + debug('Caught exception while looking for batch file (%s)' % msg) + warn_msg = "VC version %s not installed. " + \ + "C/C++ compilers are most likely not set correctly.\n" + \ + " Installed versions are: %s" + warn_msg = warn_msg % (version, cached_get_installed_vcs(env)) + SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg) + continue + + # Try to use the located batch file for this host/target platform combo + debug('vc.py:msvc_find_valid_batch_script() use_script 2 %s, args:%s\n' % (repr(vc_script), arg)) + found = None + if vc_script: + try: + d = script_env(vc_script, args=arg) + found = vc_script + except BatchFileExecutionError as e: + debug('vc.py:msvc_find_valid_batch_script() use_script 3: failed running VC script %s: %s: Error:%s'%(repr(vc_script),arg,e)) + vc_script=None + continue + if not vc_script and sdk_script: + debug('vc.py:msvc_find_valid_batch_script() use_script 4: trying sdk script: %s'%(sdk_script)) + try: + d = script_env(sdk_script) + found = sdk_script + except BatchFileExecutionError as e: + debug('vc.py:msvc_find_valid_batch_script() use_script 5: failed running SDK script %s: Error:%s'%(repr(sdk_script),e)) + continue + elif not vc_script and not sdk_script: + debug('vc.py:msvc_find_valid_batch_script() use_script 6: Neither VC script nor SDK script found') + continue + + debug("vc.py:msvc_find_valid_batch_script() Found a working script/target: %s/%s"%(repr(found),arg)) + break # We've found a working target_platform, so stop looking + + # If we cannot find a viable installed compiler, reset the TARGET_ARCH + # To it's initial value + if not d: + env['TARGET_ARCH']=req_target_platform + + return d + + +def msvc_setup_env(env): + debug('msvc_setup_env()') + + version = get_default_version(env) + if version is None: + warn_msg = "No version of Visual Studio compiler found - C/C++ " \ + "compilers most likely not set correctly" + SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg) + return None + debug('msvc_setup_env: using specified MSVC version %s\n' % repr(version)) + + # XXX: we set-up both MSVS version for backward + # compatibility with the msvs tool + env['MSVC_VERSION'] = version + env['MSVS_VERSION'] = version + env['MSVS'] = {} + + + use_script = env.get('MSVC_USE_SCRIPT', True) + if SCons.Util.is_String(use_script): + debug('vc.py:msvc_setup_env() use_script 1 %s\n' % repr(use_script)) + d = script_env(use_script) + elif use_script: + d = msvc_find_valid_batch_script(env,version) + debug('vc.py:msvc_setup_env() use_script 2 %s\n' % d) + if not d: + return d + else: + debug('MSVC_USE_SCRIPT set to False') + warn_msg = "MSVC_USE_SCRIPT set to False, assuming environment " \ + "set correctly." + SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg) + return None + + for k, v in d.items(): + debug('vc.py:msvc_setup_env() env:%s -> %s'%(k,v)) + env.PrependENVPath(k, v, delete_existing=True) + + # final check to issue a warning if the compiler is not present + msvc_cl = find_program_path(env, 'cl') + if not msvc_cl: + SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, + "Could not find MSVC compiler 'cl', it may need to be installed separately with Visual Studio") + +def msvc_exists(env=None, version=None): + vcs = cached_get_installed_vcs(env) + if version is None: + return len(vcs) > 0 + return version in vcs diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/MSCommon/vs.py b/tools/scons/scons-local-3.0.5/SCons/Tool/MSCommon/vs.py new file mode 100755 index 0000000000..f7f3de2843 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/MSCommon/vs.py @@ -0,0 +1,572 @@ +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/MSCommon/vs.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +__doc__ = """Module to detect Visual Studio and/or Visual C/C++ +""" + +import os + +import SCons.Errors +import SCons.Util + +from .common import debug, \ + get_output, \ + is_win64, \ + normalize_env, \ + parse_output, \ + read_reg + +import SCons.Tool.MSCommon.vc + +class VisualStudio(object): + """ + An abstract base class for trying to find installed versions of + Visual Studio. + """ + def __init__(self, version, **kw): + self.version = version + kw['vc_version'] = kw.get('vc_version', version) + kw['sdk_version'] = kw.get('sdk_version', version) + self.__dict__.update(kw) + self._cache = {} + + def find_batch_file(self): + vs_dir = self.get_vs_dir() + if not vs_dir: + debug('find_executable(): no vs_dir') + return None + batch_file = os.path.join(vs_dir, self.batch_file_path) + batch_file = os.path.normpath(batch_file) + if not os.path.isfile(batch_file): + debug('find_batch_file(): %s not on file system' % batch_file) + return None + return batch_file + + def find_vs_dir_by_vc(self): + SCons.Tool.MSCommon.vc.get_installed_vcs() + dir = SCons.Tool.MSCommon.vc.find_vc_pdir(self.vc_version) + if not dir: + debug('find_vs_dir_by_vc(): no installed VC %s' % self.vc_version) + return None + return os.path.abspath(os.path.join(dir, os.pardir)) + + def find_vs_dir_by_reg(self): + root = 'Software\\' + + if is_win64(): + root = root + 'Wow6432Node\\' + for key in self.hkeys: + if key=='use_dir': + return self.find_vs_dir_by_vc() + key = root + key + try: + comps = read_reg(key) + except SCons.Util.WinError as e: + debug('find_vs_dir_by_reg(): no VS registry key {}'.format(repr(key))) + else: + debug('find_vs_dir_by_reg(): found VS in registry: {}'.format(comps)) + return comps + return None + + def find_vs_dir(self): + """ Can use registry or location of VC to find vs dir + First try to find by registry, and if that fails find via VC dir + """ + + vs_dir=self.find_vs_dir_by_reg() + if not vs_dir: + vs_dir = self.find_vs_dir_by_vc() + debug('find_vs_dir(): found VS in ' + str(vs_dir )) + return vs_dir + + def find_executable(self): + vs_dir = self.get_vs_dir() + if not vs_dir: + debug('find_executable(): no vs_dir ({})'.format(vs_dir)) + return None + executable = os.path.join(vs_dir, self.executable_path) + executable = os.path.normpath(executable) + if not os.path.isfile(executable): + debug('find_executable(): {} not on file system'.format(executable)) + return None + return executable + + def get_batch_file(self): + try: + return self._cache['batch_file'] + except KeyError: + batch_file = self.find_batch_file() + self._cache['batch_file'] = batch_file + return batch_file + + def get_executable(self): + try: + debug('get_executable using cache:%s'%self._cache['executable']) + return self._cache['executable'] + except KeyError: + executable = self.find_executable() + self._cache['executable'] = executable + debug('get_executable not in cache:%s'%executable) + return executable + + def get_vs_dir(self): + try: + return self._cache['vs_dir'] + except KeyError: + vs_dir = self.find_vs_dir() + self._cache['vs_dir'] = vs_dir + return vs_dir + + def get_supported_arch(self): + try: + return self._cache['supported_arch'] + except KeyError: + # RDEVE: for the time being use hardcoded lists + # supported_arch = self.find_supported_arch() + self._cache['supported_arch'] = self.supported_arch + return self.supported_arch + + def reset(self): + self._cache = {} + +# The list of supported Visual Studio versions we know how to detect. +# +# How to look for .bat file ? +# - VS 2008 Express (x86): +# * from registry key productdir, gives the full path to vsvarsall.bat. In +# HKEY_LOCAL_MACHINE): +# Software\Microsoft\VCEpress\9.0\Setup\VC\productdir +# * from environmnent variable VS90COMNTOOLS: the path is then ..\..\VC +# relatively to the path given by the variable. +# +# - VS 2008 Express (WoW6432: 32 bits on windows x64): +# Software\Wow6432Node\Microsoft\VCEpress\9.0\Setup\VC\productdir +# +# - VS 2005 Express (x86): +# * from registry key productdir, gives the full path to vsvarsall.bat. In +# HKEY_LOCAL_MACHINE): +# Software\Microsoft\VCEpress\8.0\Setup\VC\productdir +# * from environmnent variable VS80COMNTOOLS: the path is then ..\..\VC +# relatively to the path given by the variable. +# +# - VS 2005 Express (WoW6432: 32 bits on windows x64): does not seem to have a +# productdir ? +# +# - VS 2003 .Net (pro edition ? x86): +# * from registry key productdir. The path is then ..\Common7\Tools\ +# relatively to the key. The key is in HKEY_LOCAL_MACHINE): +# Software\Microsoft\VisualStudio\7.1\Setup\VC\productdir +# * from environmnent variable VS71COMNTOOLS: the path is the full path to +# vsvars32.bat +# +# - VS 98 (VS 6): +# * from registry key productdir. The path is then Bin +# relatively to the key. The key is in HKEY_LOCAL_MACHINE): +# Software\Microsoft\VisualStudio\6.0\Setup\VC98\productdir +# +# The first version found in the list is the one used by default if +# there are multiple versions installed. Barring good reasons to +# the contrary, this means we should list versions from most recent +# to oldest. Pro versions get listed before Express versions on the +# assumption that, by default, you'd rather use the version you paid +# good money for in preference to whatever Microsoft makes available +# for free. +# +# If you update this list, update _VCVER and _VCVER_TO_PRODUCT_DIR in +# Tool/MSCommon/vc.py, and the MSVC_VERSION documentation in Tool/msvc.xml. + +SupportedVSList = [ + # Visual Studio 2017 + VisualStudio('14.1', + vc_version='14.1', + sdk_version='10.0A', + hkeys=[], + common_tools_var='VS150COMNTOOLS', + executable_path=r'Common7\IDE\devenv.com', + batch_file_path=r'VC\Auxiliary\Build\vsvars32.bat', + supported_arch=['x86', 'amd64', "arm"], + ), + + # Visual Studio 2015 + VisualStudio('14.0', + vc_version='14.0', + sdk_version='10.0', + hkeys=[r'Microsoft\VisualStudio\14.0\Setup\VS\ProductDir'], + common_tools_var='VS140COMNTOOLS', + executable_path=r'Common7\IDE\devenv.com', + batch_file_path=r'Common7\Tools\vsvars32.bat', + supported_arch=['x86', 'amd64', "arm"], + ), + + # Visual C++ 2015 Express Edition (for Desktop) + VisualStudio('14.0Exp', + vc_version='14.0', + sdk_version='10.0A', + hkeys=[r'Microsoft\VisualStudio\14.0\Setup\VS\ProductDir'], + common_tools_var='VS140COMNTOOLS', + executable_path=r'Common7\IDE\WDExpress.exe', + batch_file_path=r'Common7\Tools\vsvars32.bat', + supported_arch=['x86', 'amd64', "arm"], + ), + + # Visual Studio 2013 + VisualStudio('12.0', + vc_version='12.0', + sdk_version='8.1A', + hkeys=[r'Microsoft\VisualStudio\12.0\Setup\VS\ProductDir'], + common_tools_var='VS120COMNTOOLS', + executable_path=r'Common7\IDE\devenv.com', + batch_file_path=r'Common7\Tools\vsvars32.bat', + supported_arch=['x86', 'amd64'], + ), + + # Visual C++ 2013 Express Edition (for Desktop) + VisualStudio('12.0Exp', + vc_version='12.0', + sdk_version='8.1A', + hkeys=[r'Microsoft\VisualStudio\12.0\Setup\VS\ProductDir'], + common_tools_var='VS120COMNTOOLS', + executable_path=r'Common7\IDE\WDExpress.exe', + batch_file_path=r'Common7\Tools\vsvars32.bat', + supported_arch=['x86', 'amd64'], + ), + + # Visual Studio 2012 + VisualStudio('11.0', + sdk_version='8.0A', + hkeys=[r'Microsoft\VisualStudio\11.0\Setup\VS\ProductDir'], + common_tools_var='VS110COMNTOOLS', + executable_path=r'Common7\IDE\devenv.com', + batch_file_path=r'Common7\Tools\vsvars32.bat', + supported_arch=['x86', 'amd64'], + ), + + # Visual C++ 2012 Express Edition (for Desktop) + VisualStudio('11.0Exp', + vc_version='11.0', + sdk_version='8.0A', + hkeys=[r'Microsoft\VisualStudio\11.0\Setup\VS\ProductDir'], + common_tools_var='VS110COMNTOOLS', + executable_path=r'Common7\IDE\WDExpress.exe', + batch_file_path=r'Common7\Tools\vsvars32.bat', + supported_arch=['x86', 'amd64'], + ), + + # Visual Studio 2010 + VisualStudio('10.0', + sdk_version='7.0A', + hkeys=[r'Microsoft\VisualStudio\10.0\Setup\VS\ProductDir'], + common_tools_var='VS100COMNTOOLS', + executable_path=r'Common7\IDE\devenv.com', + batch_file_path=r'Common7\Tools\vsvars32.bat', + supported_arch=['x86', 'amd64'], + ), + + # Visual C++ 2010 Express Edition + VisualStudio('10.0Exp', + vc_version='10.0', + sdk_version='7.0A', + hkeys=[r'Microsoft\VCExpress\10.0\Setup\VS\ProductDir'], + common_tools_var='VS100COMNTOOLS', + executable_path=r'Common7\IDE\VCExpress.exe', + batch_file_path=r'Common7\Tools\vsvars32.bat', + supported_arch=['x86'], + ), + + # Visual Studio 2008 + VisualStudio('9.0', + sdk_version='6.0A', + hkeys=[r'Microsoft\VisualStudio\9.0\Setup\VS\ProductDir'], + common_tools_var='VS90COMNTOOLS', + executable_path=r'Common7\IDE\devenv.com', + batch_file_path=r'Common7\Tools\vsvars32.bat', + supported_arch=['x86', 'amd64'], + ), + + # Visual C++ 2008 Express Edition + VisualStudio('9.0Exp', + vc_version='9.0', + sdk_version='6.0A', + hkeys=[r'Microsoft\VCExpress\9.0\Setup\VS\ProductDir'], + common_tools_var='VS90COMNTOOLS', + executable_path=r'Common7\IDE\VCExpress.exe', + batch_file_path=r'Common7\Tools\vsvars32.bat', + supported_arch=['x86'], + ), + + # Visual Studio 2005 + VisualStudio('8.0', + sdk_version='6.0A', + hkeys=[r'Microsoft\VisualStudio\8.0\Setup\VS\ProductDir'], + common_tools_var='VS80COMNTOOLS', + executable_path=r'Common7\IDE\devenv.com', + batch_file_path=r'Common7\Tools\vsvars32.bat', + default_dirname='Microsoft Visual Studio 8', + supported_arch=['x86', 'amd64'], + ), + + # Visual C++ 2005 Express Edition + VisualStudio('8.0Exp', + vc_version='8.0Exp', + sdk_version='6.0A', + hkeys=[r'Microsoft\VCExpress\8.0\Setup\VS\ProductDir'], + common_tools_var='VS80COMNTOOLS', + executable_path=r'Common7\IDE\VCExpress.exe', + batch_file_path=r'Common7\Tools\vsvars32.bat', + default_dirname='Microsoft Visual Studio 8', + supported_arch=['x86'], + ), + + # Visual Studio .NET 2003 + VisualStudio('7.1', + sdk_version='6.0', + hkeys=[r'Microsoft\VisualStudio\7.1\Setup\VS\ProductDir'], + common_tools_var='VS71COMNTOOLS', + executable_path=r'Common7\IDE\devenv.com', + batch_file_path=r'Common7\Tools\vsvars32.bat', + default_dirname='Microsoft Visual Studio .NET 2003', + supported_arch=['x86'], + ), + + # Visual Studio .NET + VisualStudio('7.0', + sdk_version='2003R2', + hkeys=[r'Microsoft\VisualStudio\7.0\Setup\VS\ProductDir'], + common_tools_var='VS70COMNTOOLS', + executable_path=r'IDE\devenv.com', + batch_file_path=r'Common7\Tools\vsvars32.bat', + default_dirname='Microsoft Visual Studio .NET', + supported_arch=['x86'], + ), + + # Visual Studio 6.0 + VisualStudio('6.0', + sdk_version='2003R1', + hkeys=[r'Microsoft\VisualStudio\6.0\Setup\Microsoft Visual Studio\ProductDir', + 'use_dir'], + common_tools_var='VS60COMNTOOLS', + executable_path=r'Common\MSDev98\Bin\MSDEV.COM', + batch_file_path=r'Common7\Tools\vsvars32.bat', + default_dirname='Microsoft Visual Studio', + supported_arch=['x86'], + ), +] + +SupportedVSMap = {} +for vs in SupportedVSList: + SupportedVSMap[vs.version] = vs + + +# Finding installed versions of Visual Studio isn't cheap, because it +# goes not only to the registry but also to the disk to sanity-check +# that there is, in fact, a Visual Studio directory there and that the +# registry entry isn't just stale. Find this information once, when +# requested, and cache it. + +InstalledVSList = None +InstalledVSMap = None + +def get_installed_visual_studios(): + global InstalledVSList + global InstalledVSMap + if InstalledVSList is None: + InstalledVSList = [] + InstalledVSMap = {} + for vs in SupportedVSList: + debug('trying to find VS %s' % vs.version) + if vs.get_executable(): + debug('found VS %s' % vs.version) + InstalledVSList.append(vs) + InstalledVSMap[vs.version] = vs + return InstalledVSList + +def reset_installed_visual_studios(): + global InstalledVSList + global InstalledVSMap + InstalledVSList = None + InstalledVSMap = None + for vs in SupportedVSList: + vs.reset() + + # Need to clear installed VC's as well as they are used in finding + # installed VS's + SCons.Tool.MSCommon.vc.reset_installed_vcs() + + +# We may be asked to update multiple construction environments with +# SDK information. When doing this, we check on-disk for whether +# the SDK has 'mfc' and 'atl' subdirectories. Since going to disk +# is expensive, cache results by directory. + +#SDKEnvironmentUpdates = {} +# +#def set_sdk_by_directory(env, sdk_dir): +# global SDKEnvironmentUpdates +# try: +# env_tuple_list = SDKEnvironmentUpdates[sdk_dir] +# except KeyError: +# env_tuple_list = [] +# SDKEnvironmentUpdates[sdk_dir] = env_tuple_list +# +# include_path = os.path.join(sdk_dir, 'include') +# mfc_path = os.path.join(include_path, 'mfc') +# atl_path = os.path.join(include_path, 'atl') +# +# if os.path.exists(mfc_path): +# env_tuple_list.append(('INCLUDE', mfc_path)) +# if os.path.exists(atl_path): +# env_tuple_list.append(('INCLUDE', atl_path)) +# env_tuple_list.append(('INCLUDE', include_path)) +# +# env_tuple_list.append(('LIB', os.path.join(sdk_dir, 'lib'))) +# env_tuple_list.append(('LIBPATH', os.path.join(sdk_dir, 'lib'))) +# env_tuple_list.append(('PATH', os.path.join(sdk_dir, 'bin'))) +# +# for variable, directory in env_tuple_list: +# env.PrependENVPath(variable, directory) + +def msvs_exists(): + return (len(get_installed_visual_studios()) > 0) + +def get_vs_by_version(msvs): + global InstalledVSMap + global SupportedVSMap + + debug('vs.py:get_vs_by_version()') + if msvs not in SupportedVSMap: + msg = "Visual Studio version %s is not supported" % repr(msvs) + raise SCons.Errors.UserError(msg) + get_installed_visual_studios() + vs = InstalledVSMap.get(msvs) + debug('InstalledVSMap:%s'%InstalledVSMap) + debug('vs.py:get_vs_by_version: found vs:%s'%vs) + # Some check like this would let us provide a useful error message + # if they try to set a Visual Studio version that's not installed. + # However, we also want to be able to run tests (like the unit + # tests) on systems that don't, or won't ever, have it installed. + # It might be worth resurrecting this, with some configurable + # setting that the tests can use to bypass the check. + #if not vs: + # msg = "Visual Studio version %s is not installed" % repr(msvs) + # raise SCons.Errors.UserError, msg + return vs + +def get_default_version(env): + """Returns the default version string to use for MSVS. + + If no version was requested by the user through the MSVS environment + variable, query all the available visual studios through + get_installed_visual_studios, and take the highest one. + + Return + ------ + version: str + the default version. + """ + if 'MSVS' not in env or not SCons.Util.is_Dict(env['MSVS']): + # get all versions, and remember them for speed later + versions = [vs.version for vs in get_installed_visual_studios()] + env['MSVS'] = {'VERSIONS' : versions} + else: + versions = env['MSVS'].get('VERSIONS', []) + + if 'MSVS_VERSION' not in env: + if versions: + env['MSVS_VERSION'] = versions[0] #use highest version by default + else: + debug('get_default_version: WARNING: no installed versions found, ' + 'using first in SupportedVSList (%s)'%SupportedVSList[0].version) + env['MSVS_VERSION'] = SupportedVSList[0].version + + env['MSVS']['VERSION'] = env['MSVS_VERSION'] + + return env['MSVS_VERSION'] + +def get_default_arch(env): + """Return the default arch to use for MSVS + + if no version was requested by the user through the MSVS_ARCH environment + variable, select x86 + + Return + ------ + arch: str + """ + arch = env.get('MSVS_ARCH', 'x86') + + msvs = InstalledVSMap.get(env['MSVS_VERSION']) + + if not msvs: + arch = 'x86' + elif not arch in msvs.get_supported_arch(): + fmt = "Visual Studio version %s does not support architecture %s" + raise SCons.Errors.UserError(fmt % (env['MSVS_VERSION'], arch)) + + return arch + +def merge_default_version(env): + version = get_default_version(env) + arch = get_default_arch(env) + +def msvs_setup_env(env): + batfilename = msvs.get_batch_file() + msvs = get_vs_by_version(version) + if msvs is None: + return + + # XXX: I think this is broken. This will silently set a bogus tool instead + # of failing, but there is no other way with the current scons tool + # framework + if batfilename is not None: + + vars = ('LIB', 'LIBPATH', 'PATH', 'INCLUDE') + + msvs_list = get_installed_visual_studios() + vscommonvarnames = [vs.common_tools_var for vs in msvs_list] + save_ENV = env['ENV'] + nenv = normalize_env(env['ENV'], + ['COMSPEC'] + vscommonvarnames, + force=True) + try: + output = get_output(batfilename, arch, env=nenv) + finally: + env['ENV'] = save_ENV + vars = parse_output(output, vars) + + for k, v in vars.items(): + env.PrependENVPath(k, v, delete_existing=1) + +def query_versions(): + """Query the system to get available versions of VS. A version is + considered when a batfile is found.""" + msvs_list = get_installed_visual_studios() + versions = [msvs.version for msvs in msvs_list] + return versions + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/PharLapCommon.py b/tools/scons/scons-local-3.0.5/SCons/Tool/PharLapCommon.py new file mode 100755 index 0000000000..b78dc2aa37 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/PharLapCommon.py @@ -0,0 +1,115 @@ +"""SCons.Tool.PharLapCommon + +This module contains common code used by all Tools for the +Phar Lap ETS tool chain. Right now, this is linkloc and +386asm. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/PharLapCommon.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os +import os.path +import SCons.Errors +import SCons.Util +import re + +def getPharLapPath(): + """Reads the registry to find the installed path of the Phar Lap ETS + development kit. + + Raises UserError if no installed version of Phar Lap can + be found.""" + + if not SCons.Util.can_read_reg: + raise SCons.Errors.InternalError("No Windows registry module was found") + try: + k=SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, + 'SOFTWARE\\Pharlap\\ETS') + val, type = SCons.Util.RegQueryValueEx(k, 'BaseDir') + + # The following is a hack...there is (not surprisingly) + # an odd issue in the Phar Lap plug in that inserts + # a bunch of junk data after the phar lap path in the + # registry. We must trim it. + idx=val.find('\0') + if idx >= 0: + val = val[:idx] + + return os.path.normpath(val) + except SCons.Util.RegError: + raise SCons.Errors.UserError("Cannot find Phar Lap ETS path in the registry. Is it installed properly?") + +REGEX_ETS_VER = re.compile(r'#define\s+ETS_VER\s+([0-9]+)') + +def getPharLapVersion(): + """Returns the version of the installed ETS Tool Suite as a + decimal number. This version comes from the ETS_VER #define in + the embkern.h header. For example, '#define ETS_VER 1010' (which + is what Phar Lap 10.1 defines) would cause this method to return + 1010. Phar Lap 9.1 does not have such a #define, but this method + will return 910 as a default. + + Raises UserError if no installed version of Phar Lap can + be found.""" + + include_path = os.path.join(getPharLapPath(), os.path.normpath("include/embkern.h")) + if not os.path.exists(include_path): + raise SCons.Errors.UserError("Cannot find embkern.h in ETS include directory.\nIs Phar Lap ETS installed properly?") + mo = REGEX_ETS_VER.search(open(include_path, 'r').read()) + if mo: + return int(mo.group(1)) + # Default return for Phar Lap 9.1 + return 910 + +def addPharLapPaths(env): + """This function adds the path to the Phar Lap binaries, includes, + and libraries, if they are not already there.""" + ph_path = getPharLapPath() + + try: + env_dict = env['ENV'] + except KeyError: + env_dict = {} + env['ENV'] = env_dict + SCons.Util.AddPathIfNotExists(env_dict, 'PATH', + os.path.join(ph_path, 'bin')) + SCons.Util.AddPathIfNotExists(env_dict, 'INCLUDE', + os.path.join(ph_path, 'include')) + SCons.Util.AddPathIfNotExists(env_dict, 'LIB', + os.path.join(ph_path, 'lib')) + SCons.Util.AddPathIfNotExists(env_dict, 'LIB', + os.path.join(ph_path, os.path.normpath('lib/vclib'))) + + env['PHARLAP_PATH'] = getPharLapPath() + env['PHARLAP_VERSION'] = str(getPharLapVersion()) + + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/__init__.py b/tools/scons/scons-local-3.0.5/SCons/Tool/__init__.py new file mode 100755 index 0000000000..fcd9bca172 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/__init__.py @@ -0,0 +1,1349 @@ +"""SCons.Tool + +SCons tool selection. + +This looks for modules that define a callable object that can modify +a construction environment as appropriate for a given tool (or tool +chain). + +Note that because this subsystem just *selects* a callable that can +modify a construction environment, it's possible for people to define +their own "tool specification" in an arbitrary callable function. No +one needs to use or tie in to this subsystem in order to roll their own +tool definition. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +__revision__ = "src/engine/SCons/Tool/__init__.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import imp +import importlib +import sys +import re +import os +import shutil + +import SCons.Builder +import SCons.Errors +import SCons.Node.FS +import SCons.Scanner +import SCons.Scanner.C +import SCons.Scanner.D +import SCons.Scanner.LaTeX +import SCons.Scanner.Prog +import SCons.Scanner.SWIG +import collections + +DefaultToolpath = [] + +CScanner = SCons.Scanner.C.CScanner() +DScanner = SCons.Scanner.D.DScanner() +LaTeXScanner = SCons.Scanner.LaTeX.LaTeXScanner() +PDFLaTeXScanner = SCons.Scanner.LaTeX.PDFLaTeXScanner() +ProgramScanner = SCons.Scanner.Prog.ProgramScanner() +SourceFileScanner = SCons.Scanner.Base({}, name='SourceFileScanner') +SWIGScanner = SCons.Scanner.SWIG.SWIGScanner() + +CSuffixes = [".c", ".C", ".cxx", ".cpp", ".c++", ".cc", + ".h", ".H", ".hxx", ".hpp", ".hh", + ".F", ".fpp", ".FPP", + ".m", ".mm", + ".S", ".spp", ".SPP", ".sx"] + +DSuffixes = ['.d'] + +IDLSuffixes = [".idl", ".IDL"] + +LaTeXSuffixes = [".tex", ".ltx", ".latex"] + +SWIGSuffixes = ['.i'] + +for suffix in CSuffixes: + SourceFileScanner.add_scanner(suffix, CScanner) + +for suffix in DSuffixes: + SourceFileScanner.add_scanner(suffix, DScanner) + +for suffix in SWIGSuffixes: + SourceFileScanner.add_scanner(suffix, SWIGScanner) + +# FIXME: what should be done here? Two scanners scan the same extensions, +# but look for different files, e.g., "picture.eps" vs. "picture.pdf". +# The builders for DVI and PDF explicitly reference their scanners +# I think that means this is not needed??? +for suffix in LaTeXSuffixes: + SourceFileScanner.add_scanner(suffix, LaTeXScanner) + SourceFileScanner.add_scanner(suffix, PDFLaTeXScanner) + +# Tool aliases are needed for those tools whos module names also +# occur in the python standard library. This causes module shadowing and +# can break using python library functions under python3 +TOOL_ALIASES = { + 'gettext': 'gettext_tool', + 'clang++': 'clangxx', +} + + +class Tool(object): + def __init__(self, name, toolpath=[], **kw): + + # Rename if there's a TOOL_ALIAS for this tool + self.name = TOOL_ALIASES.get(name, name) + self.toolpath = toolpath + DefaultToolpath + # remember these so we can merge them into the call + self.init_kw = kw + + module = self._tool_module() + self.generate = module.generate + self.exists = module.exists + if hasattr(module, 'options'): + self.options = module.options + + def _load_dotted_module_py2(self, short_name, full_name, searchpaths=None): + splitname = short_name.split('.') + index = 0 + srchpths = searchpaths + for item in splitname: + file, path, desc = imp.find_module(item, srchpths) + mod = imp.load_module(full_name, file, path, desc) + srchpths = [path] + return mod, file + + def _tool_module(self): + oldpythonpath = sys.path + sys.path = self.toolpath + sys.path + # sys.stderr.write("Tool:%s\nPATH:%s\n"%(self.name,sys.path)) + + if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and sys.version_info[1] in (0, 1, 2, 3, 4)): + # Py 2 code + try: + try: + file = None + try: + mod, file = self._load_dotted_module_py2(self.name, self.name, self.toolpath) + return mod + finally: + if file: + file.close() + except ImportError as e: + splitname = self.name.split('.') + if str(e) != "No module named %s" % splitname[0]: + raise SCons.Errors.EnvironmentError(e) + try: + import zipimport + except ImportError: + pass + else: + for aPath in self.toolpath: + try: + importer = zipimport.zipimporter(aPath) + return importer.load_module(self.name) + except ImportError as e: + pass + finally: + sys.path = oldpythonpath + elif sys.version_info[1] > 4: + # From: http://stackoverflow.com/questions/67631/how-to-import-a-module-given-the-full-path/67692#67692 + # import importlib.util + # spec = importlib.util.spec_from_file_location("module.name", "/path/to/file.py") + # foo = importlib.util.module_from_spec(spec) + # spec.loader.exec_module(foo) + # foo.MyClass() + # Py 3 code + + # import pdb; pdb.set_trace() + import importlib.util + + # sys.stderr.write("toolpath:%s\n" % self.toolpath) + # sys.stderr.write("SCONS.TOOL path:%s\n" % sys.modules['SCons.Tool'].__path__) + debug = False + spec = None + found_name = self.name + add_to_scons_tools_namespace = False + for path in self.toolpath: + sepname = self.name.replace('.', os.path.sep) + file_path = os.path.join(path, "%s.py" % sepname) + file_package = os.path.join(path, sepname) + + if debug: sys.stderr.write("Trying:%s %s\n" % (file_path, file_package)) + + if os.path.isfile(file_path): + spec = importlib.util.spec_from_file_location(self.name, file_path) + if debug: print("file_Path:%s FOUND" % file_path) + break + elif os.path.isdir(file_package): + file_package = os.path.join(file_package, '__init__.py') + spec = importlib.util.spec_from_file_location(self.name, file_package) + if debug: print("PACKAGE:%s Found" % file_package) + break + + else: + continue + + if spec is None: + if debug: sys.stderr.write("NO SPEC :%s\n" % self.name) + spec = importlib.util.find_spec("." + self.name, package='SCons.Tool') + if spec: + found_name = 'SCons.Tool.' + self.name + add_to_scons_tools_namespace = True + if debug: sys.stderr.write("Spec Found? .%s :%s\n" % (self.name, spec)) + + if spec is None: + error_string = "No module named %s" % self.name + raise SCons.Errors.EnvironmentError(error_string) + + module = importlib.util.module_from_spec(spec) + if module is None: + if debug: print("MODULE IS NONE:%s" % self.name) + error_string = "No module named %s" % self.name + raise SCons.Errors.EnvironmentError(error_string) + + # Don't reload a tool we already loaded. + sys_modules_value = sys.modules.get(found_name, False) + + found_module = None + if sys_modules_value and sys_modules_value.__file__ == spec.origin: + found_module = sys.modules[found_name] + else: + # Not sure what to do in the case that there already + # exists sys.modules[self.name] but the source file is + # different.. ? + module = spec.loader.load_module(spec.name) + + sys.modules[found_name] = module + if add_to_scons_tools_namespace: + # If we found it in SCons.Tool, then add it to the module + setattr(SCons.Tool, self.name, module) + + found_module = module + + if found_module is not None: + sys.path = oldpythonpath + return found_module + + sys.path = oldpythonpath + + full_name = 'SCons.Tool.' + self.name + try: + return sys.modules[full_name] + except KeyError: + try: + smpath = sys.modules['SCons.Tool'].__path__ + try: + module, file = self._load_dotted_module_py2(self.name, full_name, smpath) + setattr(SCons.Tool, self.name, module) + if file: + file.close() + return module + except ImportError as e: + if str(e) != "No module named %s" % self.name: + raise SCons.Errors.EnvironmentError(e) + try: + import zipimport + importer = zipimport.zipimporter(sys.modules['SCons.Tool'].__path__[0]) + module = importer.load_module(full_name) + setattr(SCons.Tool, self.name, module) + return module + except ImportError as e: + m = "No tool named '%s': %s" % (self.name, e) + raise SCons.Errors.EnvironmentError(m) + except ImportError as e: + m = "No tool named '%s': %s" % (self.name, e) + raise SCons.Errors.EnvironmentError(m) + + def __call__(self, env, *args, **kw): + if self.init_kw is not None: + # Merge call kws into init kws; + # but don't bash self.init_kw. + if kw is not None: + call_kw = kw + kw = self.init_kw.copy() + kw.update(call_kw) + else: + kw = self.init_kw + env.Append(TOOLS=[self.name]) + if hasattr(self, 'options'): + import SCons.Variables + if 'options' not in env: + from SCons.Script import ARGUMENTS + env['options'] = SCons.Variables.Variables(args=ARGUMENTS) + opts = env['options'] + + self.options(opts) + opts.Update(env) + + self.generate(env, *args, **kw) + + def __str__(self): + return self.name + + +########################################################################## +# Create common executable program / library / object builders + +def createProgBuilder(env): + """This is a utility function that creates the Program + Builder in an Environment if it is not there already. + + If it is already there, we return the existing one. + """ + + try: + program = env['BUILDERS']['Program'] + except KeyError: + import SCons.Defaults + program = SCons.Builder.Builder(action=SCons.Defaults.LinkAction, + emitter='$PROGEMITTER', + prefix='$PROGPREFIX', + suffix='$PROGSUFFIX', + src_suffix='$OBJSUFFIX', + src_builder='Object', + target_scanner=ProgramScanner) + env['BUILDERS']['Program'] = program + + return program + + +def createStaticLibBuilder(env): + """This is a utility function that creates the StaticLibrary + Builder in an Environment if it is not there already. + + If it is already there, we return the existing one. + """ + + try: + static_lib = env['BUILDERS']['StaticLibrary'] + except KeyError: + action_list = [SCons.Action.Action("$ARCOM", "$ARCOMSTR")] + if env.get('RANLIB', False) or env.Detect('ranlib'): + ranlib_action = SCons.Action.Action("$RANLIBCOM", "$RANLIBCOMSTR") + action_list.append(ranlib_action) + + static_lib = SCons.Builder.Builder(action=action_list, + emitter='$LIBEMITTER', + prefix='$LIBPREFIX', + suffix='$LIBSUFFIX', + src_suffix='$OBJSUFFIX', + src_builder='StaticObject') + env['BUILDERS']['StaticLibrary'] = static_lib + env['BUILDERS']['Library'] = static_lib + + return static_lib + + +def _call_linker_cb(env, callback, args, result=None): + """Returns the result of env['LINKCALLBACKS'][callback](*args) + if env['LINKCALLBACKS'] is a dictionary and env['LINKCALLBACKS'][callback] + is callable. If these conditions are not met, return the value provided as + the *result* argument. This function is mainly used for generating library + info such as versioned suffixes, symlink maps, sonames etc. by delegating + the core job to callbacks configured by current linker tool""" + + Verbose = False + + if Verbose: + print('_call_linker_cb: args=%r' % args) + print('_call_linker_cb: callback=%r' % callback) + + try: + cbfun = env['LINKCALLBACKS'][callback] + except (KeyError, TypeError): + if Verbose: + print('_call_linker_cb: env["LINKCALLBACKS"][%r] not found or can not be used' % callback) + pass + else: + if Verbose: + print('_call_linker_cb: env["LINKCALLBACKS"][%r] found' % callback) + print('_call_linker_cb: env["LINKCALLBACKS"][%r]=%r' % (callback, cbfun)) + if isinstance(cbfun, collections.Callable): + if Verbose: + print('_call_linker_cb: env["LINKCALLBACKS"][%r] is callable' % callback) + result = cbfun(env, *args) + return result + + +def _call_env_subst(env, string, *args, **kw): + kw2 = {} + for k in ('raw', 'target', 'source', 'conv', 'executor'): + try: + kw2[k] = kw[k] + except KeyError: + pass + return env.subst(string, *args, **kw2) + + +class _ShLibInfoSupport(object): + def get_libtype(self): + return 'ShLib' + + def get_lib_prefix(self, env, *args, **kw): + return _call_env_subst(env, '$SHLIBPREFIX', *args, **kw) + + def get_lib_suffix(self, env, *args, **kw): + return _call_env_subst(env, '$SHLIBSUFFIX', *args, **kw) + + def get_lib_version(self, env, *args, **kw): + return _call_env_subst(env, '$SHLIBVERSION', *args, **kw) + + def get_lib_noversionsymlinks(self, env, *args, **kw): + return _call_env_subst(env, '$SHLIBNOVERSIONSYMLINKS', *args, **kw) + + +class _LdModInfoSupport(object): + def get_libtype(self): + return 'LdMod' + + def get_lib_prefix(self, env, *args, **kw): + return _call_env_subst(env, '$LDMODULEPREFIX', *args, **kw) + + def get_lib_suffix(self, env, *args, **kw): + return _call_env_subst(env, '$LDMODULESUFFIX', *args, **kw) + + def get_lib_version(self, env, *args, **kw): + return _call_env_subst(env, '$LDMODULEVERSION', *args, **kw) + + def get_lib_noversionsymlinks(self, env, *args, **kw): + return _call_env_subst(env, '$LDMODULENOVERSIONSYMLINKS', *args, **kw) + + +class _ImpLibInfoSupport(object): + def get_libtype(self): + return 'ImpLib' + + def get_lib_prefix(self, env, *args, **kw): + return _call_env_subst(env, '$IMPLIBPREFIX', *args, **kw) + + def get_lib_suffix(self, env, *args, **kw): + return _call_env_subst(env, '$IMPLIBSUFFIX', *args, **kw) + + def get_lib_version(self, env, *args, **kw): + version = _call_env_subst(env, '$IMPLIBVERSION', *args, **kw) + if not version: + try: + lt = kw['implib_libtype'] + except KeyError: + pass + else: + if lt == 'ShLib': + version = _call_env_subst(env, '$SHLIBVERSION', *args, **kw) + elif lt == 'LdMod': + version = _call_env_subst(env, '$LDMODULEVERSION', *args, **kw) + return version + + def get_lib_noversionsymlinks(self, env, *args, **kw): + disable = None + try: + env['IMPLIBNOVERSIONSYMLINKS'] + except KeyError: + try: + lt = kw['implib_libtype'] + except KeyError: + pass + else: + if lt == 'ShLib': + disable = _call_env_subst(env, '$SHLIBNOVERSIONSYMLINKS', *args, **kw) + elif lt == 'LdMod': + disable = _call_env_subst(env, '$LDMODULENOVERSIONSYMLINKS', *args, **kw) + else: + disable = _call_env_subst(env, '$IMPLIBNOVERSIONSYMLINKS', *args, **kw) + return disable + + +class _LibInfoGeneratorBase(object): + """Generator base class for library-related info such as suffixes for + versioned libraries, symlink maps, sonames etc. It handles commonities + of SharedLibrary and LoadableModule + """ + _support_classes = {'ShLib': _ShLibInfoSupport, + 'LdMod': _LdModInfoSupport, + 'ImpLib': _ImpLibInfoSupport} + + def __init__(self, libtype, infoname): + self.set_libtype(libtype) + self.set_infoname(infoname) + + def set_libtype(self, libtype): + try: + support_class = self._support_classes[libtype] + except KeyError: + raise ValueError('unsupported libtype %r' % libtype) + self._support = support_class() + + def get_libtype(self): + return self._support.get_libtype() + + def set_infoname(self, infoname): + self.infoname = infoname + + def get_infoname(self): + return self.infoname + + def get_lib_prefix(self, env, *args, **kw): + return self._support.get_lib_prefix(env, *args, **kw) + + def get_lib_suffix(self, env, *args, **kw): + return self._support.get_lib_suffix(env, *args, **kw) + + def get_lib_version(self, env, *args, **kw): + return self._support.get_lib_version(env, *args, **kw) + + def get_lib_noversionsymlinks(self, env, *args, **kw): + return self._support.get_lib_noversionsymlinks(env, *args, **kw) + + # Returns name of generator linker callback that shall be used to generate + # our info for a versioned library. For example, if our libtype is 'ShLib' + # and infoname is 'Prefix', it would return 'VersionedShLibPrefix'. + def get_versioned_lib_info_generator(self, **kw): + try: + libtype = kw['generator_libtype'] + except KeyError: + libtype = self.get_libtype() + infoname = self.get_infoname() + return 'Versioned%s%s' % (libtype, infoname) + + def generate_versioned_lib_info(self, env, args, result=None, **kw): + callback = self.get_versioned_lib_info_generator(**kw) + return _call_linker_cb(env, callback, args, result) + + +class _LibPrefixGenerator(_LibInfoGeneratorBase): + """Library prefix generator, used as target_prefix in SharedLibrary and + LoadableModule builders""" + + def __init__(self, libtype): + super(_LibPrefixGenerator, self).__init__(libtype, 'Prefix') + + def __call__(self, env, sources=None, **kw): + Verbose = False + + if sources and 'source' not in kw: + kw2 = kw.copy() + kw2['source'] = sources + else: + kw2 = kw + + prefix = self.get_lib_prefix(env, **kw2) + if Verbose: + print("_LibPrefixGenerator: input prefix=%r" % prefix) + + version = self.get_lib_version(env, **kw2) + if Verbose: + print("_LibPrefixGenerator: version=%r" % version) + + if version: + prefix = self.generate_versioned_lib_info(env, [prefix, version], prefix, **kw2) + + if Verbose: + print("_LibPrefixGenerator: return prefix=%r" % prefix) + return prefix + + +ShLibPrefixGenerator = _LibPrefixGenerator('ShLib') +LdModPrefixGenerator = _LibPrefixGenerator('LdMod') +ImpLibPrefixGenerator = _LibPrefixGenerator('ImpLib') + + +class _LibSuffixGenerator(_LibInfoGeneratorBase): + """Library suffix generator, used as target_suffix in SharedLibrary and + LoadableModule builders""" + + def __init__(self, libtype): + super(_LibSuffixGenerator, self).__init__(libtype, 'Suffix') + + def __call__(self, env, sources=None, **kw): + Verbose = False + + if sources and 'source' not in kw: + kw2 = kw.copy() + kw2['source'] = sources + else: + kw2 = kw + + suffix = self.get_lib_suffix(env, **kw2) + if Verbose: + print("_LibSuffixGenerator: input suffix=%r" % suffix) + + version = self.get_lib_version(env, **kw2) + if Verbose: + print("_LibSuffixGenerator: version=%r" % version) + + if version: + suffix = self.generate_versioned_lib_info(env, [suffix, version], suffix, **kw2) + + if Verbose: + print("_LibSuffixGenerator: return suffix=%r" % suffix) + return suffix + + +ShLibSuffixGenerator = _LibSuffixGenerator('ShLib') +LdModSuffixGenerator = _LibSuffixGenerator('LdMod') +ImpLibSuffixGenerator = _LibSuffixGenerator('ImpLib') + + +class _LibSymlinkGenerator(_LibInfoGeneratorBase): + """Library symlink map generator. It generates a list of symlinks that + should be created by SharedLibrary or LoadableModule builders""" + + def __init__(self, libtype): + super(_LibSymlinkGenerator, self).__init__(libtype, 'Symlinks') + + def __call__(self, env, libnode, **kw): + Verbose = False + + if libnode and 'target' not in kw: + kw2 = kw.copy() + kw2['target'] = libnode + else: + kw2 = kw + + if Verbose: + print("_LibSymLinkGenerator: libnode=%r" % libnode.get_path()) + + symlinks = None + + version = self.get_lib_version(env, **kw2) + disable = self.get_lib_noversionsymlinks(env, **kw2) + if Verbose: + print('_LibSymlinkGenerator: version=%r' % version) + print('_LibSymlinkGenerator: disable=%r' % disable) + + if version and not disable: + prefix = self.get_lib_prefix(env, **kw2) + suffix = self.get_lib_suffix(env, **kw2) + symlinks = self.generate_versioned_lib_info(env, [libnode, version, prefix, suffix], **kw2) + + if Verbose: + print('_LibSymlinkGenerator: return symlinks=%r' % StringizeLibSymlinks(symlinks)) + return symlinks + + +ShLibSymlinkGenerator = _LibSymlinkGenerator('ShLib') +LdModSymlinkGenerator = _LibSymlinkGenerator('LdMod') +ImpLibSymlinkGenerator = _LibSymlinkGenerator('ImpLib') + + +class _LibNameGenerator(_LibInfoGeneratorBase): + """Generates "unmangled" library name from a library file node. + + Generally, it's thought to revert modifications done by prefix/suffix + generators (_LibPrefixGenerator/_LibSuffixGenerator) used by a library + builder. For example, on gnulink the suffix generator used by SharedLibrary + builder appends $SHLIBVERSION to $SHLIBSUFFIX producing node name which + ends with "$SHLIBSUFFIX.$SHLIBVERSION". Correspondingly, the implementation + of _LibNameGenerator replaces "$SHLIBSUFFIX.$SHLIBVERSION" with + "$SHLIBSUFFIX" in the node's basename. So that, if $SHLIBSUFFIX is ".so", + $SHLIBVERSION is "0.1.2" and the node path is "/foo/bar/libfoo.so.0.1.2", + the _LibNameGenerator shall return "libfoo.so". Other link tools may + implement it's own way of library name unmangling. + """ + + def __init__(self, libtype): + super(_LibNameGenerator, self).__init__(libtype, 'Name') + + def __call__(self, env, libnode, **kw): + """Returns "demangled" library name""" + Verbose = False + + if libnode and 'target' not in kw: + kw2 = kw.copy() + kw2['target'] = libnode + else: + kw2 = kw + + if Verbose: + print("_LibNameGenerator: libnode=%r" % libnode.get_path()) + + version = self.get_lib_version(env, **kw2) + if Verbose: + print('_LibNameGenerator: version=%r' % version) + + name = None + if version: + prefix = self.get_lib_prefix(env, **kw2) + suffix = self.get_lib_suffix(env, **kw2) + name = self.generate_versioned_lib_info(env, [libnode, version, prefix, suffix], **kw2) + + if not name: + name = os.path.basename(libnode.get_path()) + + if Verbose: + print('_LibNameGenerator: return name=%r' % name) + + return name + + +ShLibNameGenerator = _LibNameGenerator('ShLib') +LdModNameGenerator = _LibNameGenerator('LdMod') +ImpLibNameGenerator = _LibNameGenerator('ImpLib') + + +class _LibSonameGenerator(_LibInfoGeneratorBase): + """Library soname generator. Returns library soname (e.g. libfoo.so.0) for + a given node (e.g. /foo/bar/libfoo.so.0.1.2)""" + + def __init__(self, libtype): + super(_LibSonameGenerator, self).__init__(libtype, 'Soname') + + def __call__(self, env, libnode, **kw): + """Returns a SONAME based on a shared library's node path""" + Verbose = False + + if libnode and 'target' not in kw: + kw2 = kw.copy() + kw2['target'] = libnode + else: + kw2 = kw + + if Verbose: + print("_LibSonameGenerator: libnode=%r" % libnode.get_path()) + + soname = _call_env_subst(env, '$SONAME', **kw2) + if not soname: + version = self.get_lib_version(env, **kw2) + if Verbose: + print("_LibSonameGenerator: version=%r" % version) + if version: + prefix = self.get_lib_prefix(env, **kw2) + suffix = self.get_lib_suffix(env, **kw2) + soname = self.generate_versioned_lib_info(env, [libnode, version, prefix, suffix], **kw2) + + if not soname: + # fallback to library name (as returned by appropriate _LibNameGenerator) + soname = _LibNameGenerator(self.get_libtype())(env, libnode) + if Verbose: + print("_LibSonameGenerator: FALLBACK: soname=%r" % soname) + + if Verbose: + print("_LibSonameGenerator: return soname=%r" % soname) + + return soname + + +ShLibSonameGenerator = _LibSonameGenerator('ShLib') +LdModSonameGenerator = _LibSonameGenerator('LdMod') + + +def StringizeLibSymlinks(symlinks): + """Converts list with pairs of nodes to list with pairs of node paths + (strings). Used mainly for debugging.""" + if SCons.Util.is_List(symlinks): + try: + return [(k.get_path(), v.get_path()) for k, v in symlinks] + except (TypeError, ValueError): + return symlinks + else: + return symlinks + + +def EmitLibSymlinks(env, symlinks, libnode, **kw): + """Used by emitters to handle (shared/versioned) library symlinks""" + Verbose = False + + # nodes involved in process... all symlinks + library + nodes = list(set([x for x, y in symlinks] + [libnode])) + + clean_targets = kw.get('clean_targets', []) + if not SCons.Util.is_List(clean_targets): + clean_targets = [clean_targets] + + for link, linktgt in symlinks: + env.SideEffect(link, linktgt) + if (Verbose): + print("EmitLibSymlinks: SideEffect(%r,%r)" % (link.get_path(), linktgt.get_path())) + clean_list = [x for x in nodes if x != linktgt] + env.Clean(list(set([linktgt] + clean_targets)), clean_list) + if (Verbose): + print("EmitLibSymlinks: Clean(%r,%r)" % (linktgt.get_path(), [x.get_path() for x in clean_list])) + + +def CreateLibSymlinks(env, symlinks): + """Physically creates symlinks. The symlinks argument must be a list in + form [ (link, linktarget), ... ], where link and linktarget are SCons + nodes. + """ + + Verbose = False + for link, linktgt in symlinks: + linktgt = link.get_dir().rel_path(linktgt) + link = link.get_path() + if (Verbose): + print("CreateLibSymlinks: preparing to add symlink %r -> %r" % (link, linktgt)) + # Delete the (previously created) symlink if exists. Let only symlinks + # to be deleted to prevent accidental deletion of source files... + if env.fs.islink(link): + env.fs.unlink(link) + if (Verbose): + print("CreateLibSymlinks: removed old symlink %r" % link) + # If a file or directory exists with the same name as link, an OSError + # will be thrown, which should be enough, I think. + env.fs.symlink(linktgt, link) + if (Verbose): + print("CreateLibSymlinks: add symlink %r -> %r" % (link, linktgt)) + return 0 + + +def LibSymlinksActionFunction(target, source, env): + for tgt in target: + symlinks = getattr(getattr(tgt, 'attributes', None), 'shliblinks', None) + if symlinks: + CreateLibSymlinks(env, symlinks) + return 0 + + +def LibSymlinksStrFun(target, source, env, *args): + cmd = None + for tgt in target: + symlinks = getattr(getattr(tgt, 'attributes', None), 'shliblinks', None) + if symlinks: + if cmd is None: cmd = "" + if cmd: cmd += "\n" + cmd += "Create symlinks for: %r" % tgt.get_path() + try: + linkstr = ', '.join(["%r->%r" % (k, v) for k, v in StringizeLibSymlinks(symlinks)]) + except (KeyError, ValueError): + pass + else: + cmd += ": %s" % linkstr + return cmd + + +LibSymlinksAction = SCons.Action.Action(LibSymlinksActionFunction, LibSymlinksStrFun) + + +def createSharedLibBuilder(env): + """This is a utility function that creates the SharedLibrary + Builder in an Environment if it is not there already. + + If it is already there, we return the existing one. + """ + + try: + shared_lib = env['BUILDERS']['SharedLibrary'] + except KeyError: + import SCons.Defaults + action_list = [SCons.Defaults.SharedCheck, + SCons.Defaults.ShLinkAction, + LibSymlinksAction] + shared_lib = SCons.Builder.Builder(action=action_list, + emitter="$SHLIBEMITTER", + prefix=ShLibPrefixGenerator, + suffix=ShLibSuffixGenerator, + target_scanner=ProgramScanner, + src_suffix='$SHOBJSUFFIX', + src_builder='SharedObject') + env['BUILDERS']['SharedLibrary'] = shared_lib + + return shared_lib + + +def createLoadableModuleBuilder(env): + """This is a utility function that creates the LoadableModule + Builder in an Environment if it is not there already. + + If it is already there, we return the existing one. + """ + + try: + ld_module = env['BUILDERS']['LoadableModule'] + except KeyError: + import SCons.Defaults + action_list = [SCons.Defaults.SharedCheck, + SCons.Defaults.LdModuleLinkAction, + LibSymlinksAction] + ld_module = SCons.Builder.Builder(action=action_list, + emitter="$LDMODULEEMITTER", + prefix=LdModPrefixGenerator, + suffix=LdModSuffixGenerator, + target_scanner=ProgramScanner, + src_suffix='$SHOBJSUFFIX', + src_builder='SharedObject') + env['BUILDERS']['LoadableModule'] = ld_module + + return ld_module + + +def createObjBuilders(env): + """This is a utility function that creates the StaticObject + and SharedObject Builders in an Environment if they + are not there already. + + If they are there already, we return the existing ones. + + This is a separate function because soooo many Tools + use this functionality. + + The return is a 2-tuple of (StaticObject, SharedObject) + """ + + try: + static_obj = env['BUILDERS']['StaticObject'] + except KeyError: + static_obj = SCons.Builder.Builder(action={}, + emitter={}, + prefix='$OBJPREFIX', + suffix='$OBJSUFFIX', + src_builder=['CFile', 'CXXFile'], + source_scanner=SourceFileScanner, + single_source=1) + env['BUILDERS']['StaticObject'] = static_obj + env['BUILDERS']['Object'] = static_obj + + try: + shared_obj = env['BUILDERS']['SharedObject'] + except KeyError: + shared_obj = SCons.Builder.Builder(action={}, + emitter={}, + prefix='$SHOBJPREFIX', + suffix='$SHOBJSUFFIX', + src_builder=['CFile', 'CXXFile'], + source_scanner=SourceFileScanner, + single_source=1) + env['BUILDERS']['SharedObject'] = shared_obj + + return (static_obj, shared_obj) + + +def createCFileBuilders(env): + """This is a utility function that creates the CFile/CXXFile + Builders in an Environment if they + are not there already. + + If they are there already, we return the existing ones. + + This is a separate function because soooo many Tools + use this functionality. + + The return is a 2-tuple of (CFile, CXXFile) + """ + + try: + c_file = env['BUILDERS']['CFile'] + except KeyError: + c_file = SCons.Builder.Builder(action={}, + emitter={}, + suffix={None: '$CFILESUFFIX'}) + env['BUILDERS']['CFile'] = c_file + + env.SetDefault(CFILESUFFIX='.c') + + try: + cxx_file = env['BUILDERS']['CXXFile'] + except KeyError: + cxx_file = SCons.Builder.Builder(action={}, + emitter={}, + suffix={None: '$CXXFILESUFFIX'}) + env['BUILDERS']['CXXFile'] = cxx_file + env.SetDefault(CXXFILESUFFIX='.cc') + + return (c_file, cxx_file) + + +########################################################################## +# Create common Java builders + +def CreateJarBuilder(env): + """The Jar builder expects a list of class files + which it can package into a jar file. + + The jar tool provides an interface for passing other types + of java files such as .java, directories or swig interfaces + and will build them to class files in which it can package + into the jar. + """ + try: + java_jar = env['BUILDERS']['JarFile'] + except KeyError: + fs = SCons.Node.FS.get_default_fs() + jar_com = SCons.Action.Action('$JARCOM', '$JARCOMSTR') + java_jar = SCons.Builder.Builder(action=jar_com, + suffix='$JARSUFFIX', + src_suffix='$JAVACLASSSUFFIX', + src_builder='JavaClassFile', + source_factory=fs.Entry) + env['BUILDERS']['JarFile'] = java_jar + return java_jar + + +def CreateJavaHBuilder(env): + try: + java_javah = env['BUILDERS']['JavaH'] + except KeyError: + fs = SCons.Node.FS.get_default_fs() + java_javah_com = SCons.Action.Action('$JAVAHCOM', '$JAVAHCOMSTR') + java_javah = SCons.Builder.Builder(action=java_javah_com, + src_suffix='$JAVACLASSSUFFIX', + target_factory=fs.Entry, + source_factory=fs.File, + src_builder='JavaClassFile') + env['BUILDERS']['JavaH'] = java_javah + return java_javah + + +def CreateJavaClassFileBuilder(env): + try: + java_class_file = env['BUILDERS']['JavaClassFile'] + except KeyError: + fs = SCons.Node.FS.get_default_fs() + javac_com = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR') + java_class_file = SCons.Builder.Builder(action=javac_com, + emitter={}, + # suffix = '$JAVACLASSSUFFIX', + src_suffix='$JAVASUFFIX', + src_builder=['JavaFile'], + target_factory=fs.Entry, + source_factory=fs.File) + env['BUILDERS']['JavaClassFile'] = java_class_file + return java_class_file + + +def CreateJavaClassDirBuilder(env): + try: + java_class_dir = env['BUILDERS']['JavaClassDir'] + except KeyError: + fs = SCons.Node.FS.get_default_fs() + javac_com = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR') + java_class_dir = SCons.Builder.Builder(action=javac_com, + emitter={}, + target_factory=fs.Dir, + source_factory=fs.Dir) + env['BUILDERS']['JavaClassDir'] = java_class_dir + return java_class_dir + + +def CreateJavaFileBuilder(env): + try: + java_file = env['BUILDERS']['JavaFile'] + except KeyError: + java_file = SCons.Builder.Builder(action={}, + emitter={}, + suffix={None: '$JAVASUFFIX'}) + env['BUILDERS']['JavaFile'] = java_file + env['JAVASUFFIX'] = '.java' + return java_file + + +class ToolInitializerMethod(object): + """ + This is added to a construction environment in place of a + method(s) normally called for a Builder (env.Object, env.StaticObject, + etc.). When called, it has its associated ToolInitializer + object search the specified list of tools and apply the first + one that exists to the construction environment. It then calls + whatever builder was (presumably) added to the construction + environment in place of this particular instance. + """ + + def __init__(self, name, initializer): + """ + Note: we store the tool name as __name__ so it can be used by + the class that attaches this to a construction environment. + """ + self.__name__ = name + self.initializer = initializer + + def get_builder(self, env): + """ + Returns the appropriate real Builder for this method name + after having the associated ToolInitializer object apply + the appropriate Tool module. + """ + builder = getattr(env, self.__name__) + + self.initializer.apply_tools(env) + + builder = getattr(env, self.__name__) + if builder is self: + # There was no Builder added, which means no valid Tool + # for this name was found (or possibly there's a mismatch + # between the name we were called by and the Builder name + # added by the Tool module). + return None + + self.initializer.remove_methods(env) + + return builder + + def __call__(self, env, *args, **kw): + """ + """ + builder = self.get_builder(env) + if builder is None: + return [], [] + return builder(*args, **kw) + + +class ToolInitializer(object): + """ + A class for delayed initialization of Tools modules. + + Instances of this class associate a list of Tool modules with + a list of Builder method names that will be added by those Tool + modules. As part of instantiating this object for a particular + construction environment, we also add the appropriate + ToolInitializerMethod objects for the various Builder methods + that we want to use to delay Tool searches until necessary. + """ + + def __init__(self, env, tools, names): + if not SCons.Util.is_List(tools): + tools = [tools] + if not SCons.Util.is_List(names): + names = [names] + self.env = env + self.tools = tools + self.names = names + self.methods = {} + for name in names: + method = ToolInitializerMethod(name, self) + self.methods[name] = method + env.AddMethod(method) + + def remove_methods(self, env): + """ + Removes the methods that were added by the tool initialization + so we no longer copy and re-bind them when the construction + environment gets cloned. + """ + for method in list(self.methods.values()): + env.RemoveMethod(method) + + def apply_tools(self, env): + """ + Searches the list of associated Tool modules for one that + exists, and applies that to the construction environment. + """ + for t in self.tools: + tool = SCons.Tool.Tool(t) + if tool.exists(env): + env.Tool(tool) + return + + # If we fall through here, there was no tool module found. + # This is where we can put an informative error message + # about the inability to find the tool. We'll start doing + # this as we cut over more pre-defined Builder+Tools to use + # the ToolInitializer class. + + +def Initializers(env): + ToolInitializer(env, ['install'], ['_InternalInstall', '_InternalInstallAs', '_InternalInstallVersionedLib']) + + def Install(self, *args, **kw): + return self._InternalInstall(*args, **kw) + + def InstallAs(self, *args, **kw): + return self._InternalInstallAs(*args, **kw) + + def InstallVersionedLib(self, *args, **kw): + return self._InternalInstallVersionedLib(*args, **kw) + + env.AddMethod(Install) + env.AddMethod(InstallAs) + env.AddMethod(InstallVersionedLib) + + +def FindTool(tools, env): + for tool in tools: + t = Tool(tool) + if t.exists(env): + return tool + return None + + +def FindAllTools(tools, env): + def ToolExists(tool, env=env): + return Tool(tool).exists(env) + + return list(filter(ToolExists, tools)) + + +def tool_list(platform, env): + other_plat_tools = [] + # XXX this logic about what tool to prefer on which platform + # should be moved into either the platform files or + # the tool files themselves. + # The search orders here are described in the man page. If you + # change these search orders, update the man page as well. + if str(platform) == 'win32': + "prefer Microsoft tools on Windows" + linkers = ['mslink', 'gnulink', 'ilink', 'linkloc', 'ilink32'] + c_compilers = ['msvc', 'mingw', 'gcc', 'intelc', 'icl', 'icc', 'cc', 'bcc32'] + cxx_compilers = ['msvc', 'intelc', 'icc', 'g++', 'cxx', 'bcc32'] + assemblers = ['masm', 'nasm', 'gas', '386asm'] + fortran_compilers = ['gfortran', 'g77', 'ifl', 'cvf', 'f95', 'f90', 'fortran'] + ars = ['mslib', 'ar', 'tlib'] + other_plat_tools = ['msvs', 'midl'] + elif str(platform) == 'os2': + "prefer IBM tools on OS/2" + linkers = ['ilink', 'gnulink', ] # 'mslink'] + c_compilers = ['icc', 'gcc', ] # 'msvc', 'cc'] + cxx_compilers = ['icc', 'g++', ] # 'msvc', 'cxx'] + assemblers = ['nasm', ] # 'masm', 'gas'] + fortran_compilers = ['ifl', 'g77'] + ars = ['ar', ] # 'mslib'] + elif str(platform) == 'irix': + "prefer MIPSPro on IRIX" + linkers = ['sgilink', 'gnulink'] + c_compilers = ['sgicc', 'gcc', 'cc'] + cxx_compilers = ['sgicxx', 'g++', 'cxx'] + assemblers = ['as', 'gas'] + fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran'] + ars = ['sgiar'] + elif str(platform) == 'sunos': + "prefer Forte tools on SunOS" + linkers = ['sunlink', 'gnulink'] + c_compilers = ['suncc', 'gcc', 'cc'] + cxx_compilers = ['suncxx', 'g++', 'cxx'] + assemblers = ['as', 'gas'] + fortran_compilers = ['sunf95', 'sunf90', 'sunf77', 'f95', 'f90', 'f77', + 'gfortran', 'g77', 'fortran'] + ars = ['sunar'] + elif str(platform) == 'hpux': + "prefer aCC tools on HP-UX" + linkers = ['hplink', 'gnulink'] + c_compilers = ['hpcc', 'gcc', 'cc'] + cxx_compilers = ['hpcxx', 'g++', 'cxx'] + assemblers = ['as', 'gas'] + fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran'] + ars = ['ar'] + elif str(platform) == 'aix': + "prefer AIX Visual Age tools on AIX" + linkers = ['aixlink', 'gnulink'] + c_compilers = ['aixcc', 'gcc', 'cc'] + cxx_compilers = ['aixcxx', 'g++', 'cxx'] + assemblers = ['as', 'gas'] + fortran_compilers = ['f95', 'f90', 'aixf77', 'g77', 'fortran'] + ars = ['ar'] + elif str(platform) == 'darwin': + "prefer GNU tools on Mac OS X, except for some linkers and IBM tools" + linkers = ['applelink', 'gnulink'] + c_compilers = ['gcc', 'cc'] + cxx_compilers = ['g++', 'cxx'] + assemblers = ['as'] + fortran_compilers = ['gfortran', 'f95', 'f90', 'g77'] + ars = ['ar'] + elif str(platform) == 'cygwin': + "prefer GNU tools on Cygwin, except for a platform-specific linker" + linkers = ['cyglink', 'mslink', 'ilink'] + c_compilers = ['gcc', 'msvc', 'intelc', 'icc', 'cc'] + cxx_compilers = ['g++', 'msvc', 'intelc', 'icc', 'cxx'] + assemblers = ['gas', 'nasm', 'masm'] + fortran_compilers = ['gfortran', 'g77', 'ifort', 'ifl', 'f95', 'f90', 'f77'] + ars = ['ar', 'mslib'] + else: + "prefer GNU tools on all other platforms" + linkers = ['gnulink', 'ilink'] + c_compilers = ['gcc', 'intelc', 'icc', 'cc'] + cxx_compilers = ['g++', 'intelc', 'icc', 'cxx'] + assemblers = ['gas', 'nasm', 'masm'] + fortran_compilers = ['gfortran', 'g77', 'ifort', 'ifl', 'f95', 'f90', 'f77'] + ars = ['ar', ] + + if not str(platform) == 'win32': + other_plat_tools += ['m4', 'rpm'] + + c_compiler = FindTool(c_compilers, env) or c_compilers[0] + + # XXX this logic about what tool provides what should somehow be + # moved into the tool files themselves. + if c_compiler and c_compiler == 'mingw': + # MinGW contains a linker, C compiler, C++ compiler, + # Fortran compiler, archiver and assembler: + cxx_compiler = None + linker = None + assembler = None + fortran_compiler = None + ar = None + else: + # Don't use g++ if the C compiler has built-in C++ support: + if c_compiler in ('msvc', 'intelc', 'icc'): + cxx_compiler = None + else: + cxx_compiler = FindTool(cxx_compilers, env) or cxx_compilers[0] + linker = FindTool(linkers, env) or linkers[0] + assembler = FindTool(assemblers, env) or assemblers[0] + fortran_compiler = FindTool(fortran_compilers, env) or fortran_compilers[0] + ar = FindTool(ars, env) or ars[0] + + d_compilers = ['dmd', 'ldc', 'gdc'] + d_compiler = FindTool(d_compilers, env) or d_compilers[0] + + other_tools = FindAllTools(other_plat_tools + [ + # TODO: merge 'install' into 'filesystem' and + # make 'filesystem' the default + 'filesystem', + 'wix', # 'midl', 'msvs', + # Parser generators + 'lex', 'yacc', + # Foreign function interface + 'rpcgen', 'swig', + # Java + 'jar', 'javac', 'javah', 'rmic', + # TeX + 'dvipdf', 'dvips', 'gs', + 'tex', 'latex', 'pdflatex', 'pdftex', + # Archivers + 'tar', 'zip', + # File builders (text) + 'textfile', + ], env) + + tools = ([linker, c_compiler, cxx_compiler, + fortran_compiler, assembler, ar, d_compiler] + + other_tools) + + return [x for x in tools if x] + + +def find_program_path(env, key_program, default_paths=[]): + """ + Find the location of key_program and then return the path it was located at. + Checking the default install locations. + Mainly for windows where tools aren't all installed in /usr/bin,etc + :param env: Current Environment() + :param key_program: Program we're using to locate the directory to add to PATH. + """ + # First search in the SCons path + path = env.WhereIs(key_program) + if (path): + return path + # then the OS path: + path = SCons.Util.WhereIs(key_program) + if (path): + return path + + # If that doesn't work try default location for mingw + save_path = env['ENV']['PATH'] + for p in default_paths: + env.AppendENVPath('PATH', p) + path = env.WhereIs(key_program) + if not path: + env['ENV']['PATH'] = save_path + return path + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/aixc++.py b/tools/scons/scons-local-3.0.5/SCons/Tool/aixc++.py new file mode 100755 index 0000000000..5ededea458 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/aixc++.py @@ -0,0 +1,43 @@ +"""SCons.Tool.aixc++ + +Tool-specific initialization for IBM xlC / Visual Age C++ compiler. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/aixc++.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +#forward proxy to the preffered cxx version +from SCons.Tool.aixcxx import * + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/aixcc.py b/tools/scons/scons-local-3.0.5/SCons/Tool/aixcc.py new file mode 100755 index 0000000000..d58184ba23 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/aixcc.py @@ -0,0 +1,74 @@ +"""SCons.Tool.aixcc + +Tool-specific initialization for IBM xlc / Visual Age C compiler. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/aixcc.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os.path + +import SCons.Platform.aix + +from . import cc + +packages = ['vac.C', 'ibmcxx.cmp'] + +def get_xlc(env): + xlc = env.get('CC', 'xlc') + return SCons.Platform.aix.get_xlc(env, xlc, packages) + +def generate(env): + """Add Builders and construction variables for xlc / Visual Age + suite to an Environment.""" + path, _cc, version = get_xlc(env) + if path and _cc: + _cc = os.path.join(path, _cc) + + if 'CC' not in env: + env['CC'] = _cc + + cc.generate(env) + + if version: + env['CCVERSION'] = version + +def exists(env): + path, _cc, version = get_xlc(env) + if path and _cc: + xlc = os.path.join(path, _cc) + if os.path.exists(xlc): + return xlc + return None + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/aixcxx.py b/tools/scons/scons-local-3.0.5/SCons/Tool/aixcxx.py new file mode 100755 index 0000000000..c5683664c8 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/aixcxx.py @@ -0,0 +1,77 @@ +"""SCons.Tool.aixc++ + +Tool-specific initialization for IBM xlC / Visual Age C++ compiler. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/aixcxx.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os.path + +import SCons.Platform.aix + +import SCons.Tool.cxx +cplusplus = SCons.Tool.cxx +#cplusplus = __import__('cxx', globals(), locals(), []) + +packages = ['vacpp.cmp.core', 'vacpp.cmp.batch', 'vacpp.cmp.C', 'ibmcxx.cmp'] + +def get_xlc(env): + xlc = env.get('CXX', 'xlC') + return SCons.Platform.aix.get_xlc(env, xlc, packages) + +def generate(env): + """Add Builders and construction variables for xlC / Visual Age + suite to an Environment.""" + path, _cxx, version = get_xlc(env) + if path and _cxx: + _cxx = os.path.join(path, _cxx) + + if 'CXX' not in env: + env['CXX'] = _cxx + + cplusplus.generate(env) + + if version: + env['CXXVERSION'] = version + +def exists(env): + path, _cxx, version = get_xlc(env) + if path and _cxx: + xlc = os.path.join(path, _cxx) + if os.path.exists(xlc): + return xlc + return None + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/aixf77.py b/tools/scons/scons-local-3.0.5/SCons/Tool/aixf77.py new file mode 100755 index 0000000000..54f196fa60 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/aixf77.py @@ -0,0 +1,80 @@ +"""engine.SCons.Tool.aixf77 + +Tool-specific initialization for IBM Visual Age f77 Fortran compiler. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/aixf77.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os.path + +#import SCons.Platform.aix + +from . import f77 + +# It would be good to look for the AIX F77 package the same way we're now +# looking for the C and C++ packages. This should be as easy as supplying +# the correct package names in the following list and uncommenting the +# SCons.Platform.aix_get_xlc() call in the function below. +packages = [] + +def get_xlf77(env): + xlf77 = env.get('F77', 'xlf77') + xlf77_r = env.get('SHF77', 'xlf77_r') + #return SCons.Platform.aix.get_xlc(env, xlf77, xlf77_r, packages) + return (None, xlf77, xlf77_r, None) + +def generate(env): + """ + Add Builders and construction variables for the Visual Age FORTRAN + compiler to an Environment. + """ + path, _f77, _shf77, version = get_xlf77(env) + if path: + _f77 = os.path.join(path, _f77) + _shf77 = os.path.join(path, _shf77) + + f77.generate(env) + + env['F77'] = _f77 + env['SHF77'] = _shf77 + +def exists(env): + path, _f77, _shf77, version = get_xlf77(env) + if path and _f77: + xlf77 = os.path.join(path, _f77) + if os.path.exists(xlf77): + return xlf77 + return None + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/aixlink.py b/tools/scons/scons-local-3.0.5/SCons/Tool/aixlink.py new file mode 100755 index 0000000000..0d808be4c1 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/aixlink.py @@ -0,0 +1,81 @@ +"""SCons.Tool.aixlink + +Tool-specific initialization for the IBM Visual Age linker. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/aixlink.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os +import os.path + +import SCons.Util + +from . import aixcc +from . import link + +import SCons.Tool.cxx +cplusplus = SCons.Tool.cxx +#cplusplus = __import__('cxx', globals(), locals(), []) + + +def smart_linkflags(source, target, env, for_signature): + if cplusplus.iscplusplus(source): + build_dir = env.subst('$BUILDDIR', target=target, source=source) + if build_dir: + return '-qtempinc=' + os.path.join(build_dir, 'tempinc') + return '' + +def generate(env): + """ + Add Builders and construction variables for Visual Age linker to + an Environment. + """ + link.generate(env) + + env['SMARTLINKFLAGS'] = smart_linkflags + env['LINKFLAGS'] = SCons.Util.CLVar('$SMARTLINKFLAGS') + env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -qmkshrobj -qsuppress=1501-218') + env['SHLIBSUFFIX'] = '.a' + +def exists(env): + # TODO: sync with link.smart_link() to choose a linker + linkers = { 'CXX': ['aixc++'], 'CC': ['aixcc'] } + alltools = [] + for langvar, linktools in linkers.items(): + if langvar in env: # use CC over CXX when user specified CC but not CXX + return SCons.Tool.FindTool(linktools, env) + alltools.extend(linktools) + return SCons.Tool.FindTool(alltools, env) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/applelink.py b/tools/scons/scons-local-3.0.5/SCons/Tool/applelink.py new file mode 100755 index 0000000000..dfb9d9d9d8 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/applelink.py @@ -0,0 +1,218 @@ +"""SCons.Tool.applelink + +Tool-specific initialization for Apple's gnu-like linker. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/applelink.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Util + +# Even though the Mac is based on the GNU toolchain, it doesn't understand +# the -rpath option, so we use the "link" tool instead of "gnulink". +from . import link + + +class AppleLinkInvalidCurrentVersionException(Exception): + pass + +class AppleLinkInvalidCompatibilityVersionException(Exception): + pass + + +def _applelib_versioned_lib_suffix(env, suffix, version): + """For suffix='.dylib' and version='0.1.2' it returns '.0.1.2.dylib'""" + Verbose = False + if Verbose: + print("_applelib_versioned_lib_suffix: suffix={!r}".format(suffix)) + print("_applelib_versioned_lib_suffix: version={!r}".format(version)) + if version not in suffix: + suffix = "." + version + suffix + if Verbose: + print("_applelib_versioned_lib_suffix: return suffix={!r}".format(suffix)) + return suffix + + +def _applelib_versioned_lib_soname(env, libnode, version, prefix, suffix, name_func): + """For libnode='/optional/dir/libfoo.X.Y.Z.dylib' it returns 'libfoo.X.dylib'""" + Verbose = False + if Verbose: + print("_applelib_versioned_lib_soname: version={!r}".format(version)) + name = name_func(env, libnode, version, prefix, suffix) + if Verbose: + print("_applelib_versioned_lib_soname: name={!r}".format(name)) + major = version.split('.')[0] + (libname,_suffix) = name.split('.') + soname = '.'.join([libname, major, _suffix]) + if Verbose: + print("_applelib_versioned_lib_soname: soname={!r}".format(soname)) + return soname + +def _applelib_versioned_shlib_soname(env, libnode, version, prefix, suffix): + return _applelib_versioned_lib_soname(env, libnode, version, prefix, suffix, link._versioned_shlib_name) + + +# User programmatically describes how SHLIBVERSION maps to values for compat/current. +_applelib_max_version_values = (65535, 255, 255) +def _applelib_check_valid_version(version_string): + """ + Check that the version # is valid. + X[.Y[.Z]] + where X 0-65535 + where Y either not specified or 0-255 + where Z either not specified or 0-255 + :param version_string: + :return: + """ + parts = version_string.split('.') + if len(parts) > 3: + return False, "Version string has too many periods [%s]"%version_string + if len(parts) <= 0: + return False, "Version string unspecified [%s]"%version_string + + for (i, p) in enumerate(parts): + try: + p_i = int(p) + except ValueError: + return False, "Version component %s (from %s) is not a number"%(p, version_string) + if p_i < 0 or p_i > _applelib_max_version_values[i]: + return False, "Version component %s (from %s) is not valid value should be between 0 and %d"%(p, version_string, _applelib_max_version_values[i]) + + return True, "" + + +def _applelib_currentVersionFromSoVersion(source, target, env, for_signature): + """ + A generator function to create the -Wl,-current_version flag if needed. + If env['APPLELINK_NO_CURRENT_VERSION'] contains a true value no flag will be generated + Otherwise if APPLELINK_CURRENT_VERSION is not specified, env['SHLIBVERSION'] + will be used. + + :param source: + :param target: + :param env: + :param for_signature: + :return: A string providing the flag to specify the current_version of the shared library + """ + if env.get('APPLELINK_NO_CURRENT_VERSION', False): + return "" + elif env.get('APPLELINK_CURRENT_VERSION', False): + version_string = env['APPLELINK_CURRENT_VERSION'] + elif env.get('SHLIBVERSION', False): + version_string = env['SHLIBVERSION'] + else: + return "" + + version_string = ".".join(version_string.split('.')[:3]) + + valid, reason = _applelib_check_valid_version(version_string) + if not valid: + raise AppleLinkInvalidCurrentVersionException(reason) + + return "-Wl,-current_version,%s" % version_string + + +def _applelib_compatVersionFromSoVersion(source, target, env, for_signature): + """ + A generator function to create the -Wl,-compatibility_version flag if needed. + If env['APPLELINK_NO_COMPATIBILITY_VERSION'] contains a true value no flag will be generated + Otherwise if APPLELINK_COMPATIBILITY_VERSION is not specified + the first two parts of env['SHLIBVERSION'] will be used with a .0 appended. + + :param source: + :param target: + :param env: + :param for_signature: + :return: A string providing the flag to specify the compatibility_version of the shared library + """ + if env.get('APPLELINK_NO_COMPATIBILITY_VERSION', False): + return "" + elif env.get('APPLELINK_COMPATIBILITY_VERSION', False): + version_string = env['APPLELINK_COMPATIBILITY_VERSION'] + elif env.get('SHLIBVERSION', False): + version_string = ".".join(env['SHLIBVERSION'].split('.')[:2] + ['0']) + else: + return "" + + if version_string is None: + return "" + + valid, reason = _applelib_check_valid_version(version_string) + if not valid: + raise AppleLinkInvalidCompatibilityVersionException(reason) + + return "-Wl,-compatibility_version,%s" % version_string + + +def generate(env): + """Add Builders and construction variables for applelink to an + Environment.""" + link.generate(env) + + env['FRAMEWORKPATHPREFIX'] = '-F' + env['_FRAMEWORKPATH'] = '${_concat(FRAMEWORKPATHPREFIX, FRAMEWORKPATH, "", __env__, RDirs)}' + + env['_FRAMEWORKS'] = '${_concat("-framework ", FRAMEWORKS, "", __env__)}' + env['LINKCOM'] = env['LINKCOM'] + ' $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS' + env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -dynamiclib') + env['SHLINKCOM'] = env['SHLINKCOM'] + ' $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS' + + + # see: http://docstore.mik.ua/orelly/unix3/mac/ch05_04.htm for proper naming + link._setup_versioned_lib_variables(env, tool = 'applelink')#, use_soname = use_soname) + env['LINKCALLBACKS'] = link._versioned_lib_callbacks() + env['LINKCALLBACKS']['VersionedShLibSuffix'] = _applelib_versioned_lib_suffix + env['LINKCALLBACKS']['VersionedShLibSoname'] = _applelib_versioned_shlib_soname + + env['_APPLELINK_CURRENT_VERSION'] = _applelib_currentVersionFromSoVersion + env['_APPLELINK_COMPATIBILITY_VERSION'] = _applelib_compatVersionFromSoVersion + env['_SHLIBVERSIONFLAGS'] = '$_APPLELINK_CURRENT_VERSION $_APPLELINK_COMPATIBILITY_VERSION ' + env['_LDMODULEVERSIONFLAGS'] = '$_APPLELINK_CURRENT_VERSION $_APPLELINK_COMPATIBILITY_VERSION ' + + # override the default for loadable modules, which are different + # on OS X than dynamic shared libs. echoing what XCode does for + # pre/suffixes: + env['LDMODULEPREFIX'] = '' + env['LDMODULESUFFIX'] = '' + env['LDMODULEFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -bundle') + env['LDMODULECOM'] = '$LDMODULE -o ${TARGET} $LDMODULEFLAGS $SOURCES $_LIBDIRFLAGS $_LIBFLAGS $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS' + + env['__SHLIBVERSIONFLAGS'] = '${__libversionflags(__env__,"SHLIBVERSION","_SHLIBVERSIONFLAGS")}' + + + +def exists(env): + return env['PLATFORM'] == 'darwin' + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/ar.py b/tools/scons/scons-local-3.0.5/SCons/Tool/ar.py new file mode 100755 index 0000000000..aee2426b6d --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/ar.py @@ -0,0 +1,63 @@ +"""SCons.Tool.ar + +Tool-specific initialization for ar (library archive). + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/ar.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Defaults +import SCons.Tool +import SCons.Util + + +def generate(env): + """Add Builders and construction variables for ar to an Environment.""" + SCons.Tool.createStaticLibBuilder(env) + + env['AR'] = 'ar' + env['ARFLAGS'] = SCons.Util.CLVar('rc') + env['ARCOM'] = '$AR $ARFLAGS $TARGET $SOURCES' + env['LIBPREFIX'] = 'lib' + env['LIBSUFFIX'] = '.a' + + if env.get('RANLIB',env.Detect('ranlib')) : + env['RANLIB'] = env.get('RANLIB','ranlib') + env['RANLIBFLAGS'] = SCons.Util.CLVar('') + env['RANLIBCOM'] = '$RANLIB $RANLIBFLAGS $TARGET' + +def exists(env): + return env.Detect('ar') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/as.py b/tools/scons/scons-local-3.0.5/SCons/Tool/as.py new file mode 100755 index 0000000000..e0d0239759 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/as.py @@ -0,0 +1,78 @@ +"""SCons.Tool.as + +Tool-specific initialization for as, the generic Posix assembler. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/as.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Defaults +import SCons.Tool +import SCons.Util + +assemblers = ['as'] + +ASSuffixes = ['.s', '.asm', '.ASM'] +ASPPSuffixes = ['.spp', '.SPP', '.sx'] +if SCons.Util.case_sensitive_suffixes('.s', '.S'): + ASPPSuffixes.extend(['.S']) +else: + ASSuffixes.extend(['.S']) + +def generate(env): + """Add Builders and construction variables for as to an Environment.""" + static_obj, shared_obj = SCons.Tool.createObjBuilders(env) + + for suffix in ASSuffixes: + static_obj.add_action(suffix, SCons.Defaults.ASAction) + shared_obj.add_action(suffix, SCons.Defaults.ASAction) + static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter) + shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter) + + for suffix in ASPPSuffixes: + static_obj.add_action(suffix, SCons.Defaults.ASPPAction) + shared_obj.add_action(suffix, SCons.Defaults.ASPPAction) + static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter) + shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter) + + env['AS'] = env.Detect(assemblers) or 'as' + env['ASFLAGS'] = SCons.Util.CLVar('') + env['ASCOM'] = '$AS $ASFLAGS -o $TARGET $SOURCES' + env['ASPPFLAGS'] = '$ASFLAGS' + env['ASPPCOM'] = '$CC $ASPPFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES' + +def exists(env): + return env.Detect(assemblers) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/bcc32.py b/tools/scons/scons-local-3.0.5/SCons/Tool/bcc32.py new file mode 100755 index 0000000000..17cd4fc390 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/bcc32.py @@ -0,0 +1,81 @@ +"""SCons.Tool.bcc32 + +XXX + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/bcc32.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os +import os.path + +import SCons.Defaults +import SCons.Tool +import SCons.Util + +def findIt(program, env): + # First search in the SCons path and then the OS path: + borwin = env.WhereIs(program) or SCons.Util.WhereIs(program) + if borwin: + dir = os.path.dirname(borwin) + env.PrependENVPath('PATH', dir) + return borwin + +def generate(env): + findIt('bcc32', env) + """Add Builders and construction variables for bcc to an + Environment.""" + static_obj, shared_obj = SCons.Tool.createObjBuilders(env) + for suffix in ['.c', '.cpp']: + static_obj.add_action(suffix, SCons.Defaults.CAction) + shared_obj.add_action(suffix, SCons.Defaults.ShCAction) + static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter) + shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter) + + env['CC'] = 'bcc32' + env['CCFLAGS'] = SCons.Util.CLVar('') + env['CFLAGS'] = SCons.Util.CLVar('') + env['CCCOM'] = '$CC -q $CFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o$TARGET $SOURCES' + env['SHCC'] = '$CC' + env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS') + env['SHCFLAGS'] = SCons.Util.CLVar('$CFLAGS') + env['SHCCCOM'] = '$SHCC -WD $SHCFLAGS $SHCCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o$TARGET $SOURCES' + env['CPPDEFPREFIX'] = '-D' + env['CPPDEFSUFFIX'] = '' + env['INCPREFIX'] = '-I' + env['INCSUFFIX'] = '' + env['SHOBJSUFFIX'] = '.dll' + env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 0 + env['CFILESUFFIX'] = '.cpp' + +def exists(env): + return findIt('bcc32', env) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/c++.py b/tools/scons/scons-local-3.0.5/SCons/Tool/c++.py new file mode 100755 index 0000000000..bdd067c4d0 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/c++.py @@ -0,0 +1,44 @@ +"""SCons.Tool.c++ + +Tool-specific initialization for generic Posix C++ compilers. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/c++.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + + +#forward proxy to the preffered cxx version +from SCons.Tool.cxx import * + + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/cc.py b/tools/scons/scons-local-3.0.5/SCons/Tool/cc.py new file mode 100755 index 0000000000..e00df4685e --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/cc.py @@ -0,0 +1,105 @@ +"""SCons.Tool.cc + +Tool-specific initialization for generic Posix C compilers. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/cc.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Tool +import SCons.Defaults +import SCons.Util + +CSuffixes = ['.c', '.m'] +if not SCons.Util.case_sensitive_suffixes('.c', '.C'): + CSuffixes.append('.C') + +def add_common_cc_variables(env): + """ + Add underlying common "C compiler" variables that + are used by multiple tools (specifically, c++). + """ + if '_CCCOMCOM' not in env: + env['_CCCOMCOM'] = '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS' + # It's a hack to test for darwin here, but the alternative + # of creating an applecc.py to contain this seems overkill. + # Maybe someday the Apple platform will require more setup and + # this logic will be moved. + env['FRAMEWORKS'] = SCons.Util.CLVar('') + env['FRAMEWORKPATH'] = SCons.Util.CLVar('') + if env['PLATFORM'] == 'darwin': + env['_CCCOMCOM'] = env['_CCCOMCOM'] + ' $_FRAMEWORKPATH' + + if 'CCFLAGS' not in env: + env['CCFLAGS'] = SCons.Util.CLVar('') + + if 'SHCCFLAGS' not in env: + env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS') + +compilers = ['cc'] + +def generate(env): + """ + Add Builders and construction variables for C compilers to an Environment. + """ + static_obj, shared_obj = SCons.Tool.createObjBuilders(env) + + for suffix in CSuffixes: + static_obj.add_action(suffix, SCons.Defaults.CAction) + shared_obj.add_action(suffix, SCons.Defaults.ShCAction) + static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter) + shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter) + + add_common_cc_variables(env) + + if 'CC' not in env: + env['CC'] = env.Detect(compilers) or compilers[0] + env['CFLAGS'] = SCons.Util.CLVar('') + env['CCCOM'] = '$CC -o $TARGET -c $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES' + env['SHCC'] = '$CC' + env['SHCFLAGS'] = SCons.Util.CLVar('$CFLAGS') + env['SHCCCOM'] = '$SHCC -o $TARGET -c $SHCFLAGS $SHCCFLAGS $_CCCOMCOM $SOURCES' + + env['CPPDEFPREFIX'] = '-D' + env['CPPDEFSUFFIX'] = '' + env['INCPREFIX'] = '-I' + env['INCSUFFIX'] = '' + env['SHOBJSUFFIX'] = '.os' + env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 0 + + env['CFILESUFFIX'] = '.c' + +def exists(env): + return env.Detect(env.get('CC', compilers)) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/clang.py b/tools/scons/scons-local-3.0.5/SCons/Tool/clang.py new file mode 100755 index 0000000000..83311eb0b7 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/clang.py @@ -0,0 +1,94 @@ +# -*- coding: utf-8; -*- + +"""SCons.Tool.clang + +Tool-specific initialization for clang. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +# __revision__ = "src/engine/SCons/Tool/clang.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +# Based on SCons/Tool/gcc.py by Paweł Tomulik 2014 as a separate tool. +# Brought into the SCons mainline by Russel Winder 2017. + +import os +import re +import subprocess +import sys + +import SCons.Util +import SCons.Tool.cc +from SCons.Tool.clangCommon import get_clang_install_dirs + + +compilers = ['clang'] + +def generate(env): + """Add Builders and construction variables for clang to an Environment.""" + SCons.Tool.cc.generate(env) + + if env['PLATFORM'] == 'win32': + # Ensure that we have a proper path for clang + clang = SCons.Tool.find_program_path(env, compilers[0], + default_paths=get_clang_install_dirs(env['PLATFORM'])) + if clang: + clang_bin_dir = os.path.dirname(clang) + env.AppendENVPath('PATH', clang_bin_dir) + + env['CC'] = env.Detect(compilers) or 'clang' + if env['PLATFORM'] in ['cygwin', 'win32']: + env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS') + else: + env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS -fPIC') + + # determine compiler version + if env['CC']: + #pipe = SCons.Action._subproc(env, [env['CC'], '-dumpversion'], + pipe = SCons.Action._subproc(env, [env['CC'], '--version'], + stdin='devnull', + stderr='devnull', + stdout=subprocess.PIPE) + if pipe.wait() != 0: return + # clang -dumpversion is of no use + line = pipe.stdout.readline() + if sys.version_info[0] > 2: + line = line.decode() + match = re.search(r'clang +version +([0-9]+(?:\.[0-9]+)+)', line) + if match: + env['CCVERSION'] = match.group(1) + +def exists(env): + return env.Detect(compilers) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/clangCommon/__init__.py b/tools/scons/scons-local-3.0.5/SCons/Tool/clangCommon/__init__.py new file mode 100755 index 0000000000..37efbf691e --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/clangCommon/__init__.py @@ -0,0 +1,17 @@ +""" +Common routines and data for clang tools +""" + +clang_win32_dirs = [ + r'C:\Program Files\LLVM\bin', + r'C:\cygwin64\bin', + r'C:\msys64', + r'C:\cygwin\bin', + r'C:\msys', +] + +def get_clang_install_dirs(platform): + if platform == 'win32': + return clang_win32_dirs + else: + return [] \ No newline at end of file diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/clangxx.py b/tools/scons/scons-local-3.0.5/SCons/Tool/clangxx.py new file mode 100755 index 0000000000..6e4199eb4e --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/clangxx.py @@ -0,0 +1,102 @@ +# -*- coding: utf-8; -*- + +"""SCons.Tool.clang++ + +Tool-specific initialization for clang++. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +# __revision__ = "src/engine/SCons/Tool/clangxx.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +# Based on SCons/Tool/g++.py by Paweł Tomulik 2014 as a separate tool. +# Brought into the SCons mainline by Russel Winder 2017. + +import os.path +import re +import subprocess +import sys + +import SCons.Tool +import SCons.Util +import SCons.Tool.cxx +from SCons.Tool.clangCommon import get_clang_install_dirs + + +compilers = ['clang++'] + +def generate(env): + """Add Builders and construction variables for clang++ to an Environment.""" + static_obj, shared_obj = SCons.Tool.createObjBuilders(env) + + SCons.Tool.cxx.generate(env) + + env['CXX'] = env.Detect(compilers) or 'clang++' + + # platform specific settings + if env['PLATFORM'] == 'aix': + env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS -mminimal-toc') + env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1 + env['SHOBJSUFFIX'] = '$OBJSUFFIX' + elif env['PLATFORM'] == 'hpux': + env['SHOBJSUFFIX'] = '.pic.o' + elif env['PLATFORM'] == 'sunos': + env['SHOBJSUFFIX'] = '.pic.o' + elif env['PLATFORM'] == 'win32': + # Ensure that we have a proper path for clang++ + clangxx = SCons.Tool.find_program_path(env, compilers[0], default_paths=get_clang_install_dirs(env['PLATFORM'])) + if clangxx: + clangxx_bin_dir = os.path.dirname(clangxx) + env.AppendENVPath('PATH', clangxx_bin_dir) + + # determine compiler version + if env['CXX']: + pipe = SCons.Action._subproc(env, [env['CXX'], '--version'], + stdin='devnull', + stderr='devnull', + stdout=subprocess.PIPE) + if pipe.wait() != 0: + return + + # clang -dumpversion is of no use + line = pipe.stdout.readline() + if sys.version_info[0] > 2: + line = line.decode() + match = re.search(r'clang +version +([0-9]+(?:\.[0-9]+)+)', line) + if match: + env['CXXVERSION'] = match.group(1) + +def exists(env): + return env.Detect(compilers) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/cvf.py b/tools/scons/scons-local-3.0.5/SCons/Tool/cvf.py new file mode 100755 index 0000000000..dde3a3e725 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/cvf.py @@ -0,0 +1,58 @@ +"""engine.SCons.Tool.cvf + +Tool-specific initialization for the Compaq Visual Fortran compiler. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/cvf.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +from . import fortran + +compilers = ['f90'] + +def generate(env): + """Add Builders and construction variables for compaq visual fortran to an Environment.""" + + fortran.generate(env) + + env['FORTRAN'] = 'f90' + env['FORTRANCOM'] = '$FORTRAN $FORTRANFLAGS $_FORTRANMODFLAG $_FORTRANINCFLAGS /compile_only ${SOURCES.windows} /object:${TARGET.windows}' + env['FORTRANPPCOM'] = '$FORTRAN $FORTRANFLAGS $CPPFLAGS $_CPPDEFFLAGS $_FORTRANMODFLAG $_FORTRANINCFLAGS /compile_only ${SOURCES.windows} /object:${TARGET.windows}' + env['SHFORTRANCOM'] = '$SHFORTRAN $SHFORTRANFLAGS $_FORTRANMODFLAG $_FORTRANINCFLAGS /compile_only ${SOURCES.windows} /object:${TARGET.windows}' + env['SHFORTRANPPCOM'] = '$SHFORTRAN $SHFORTRANFLAGS $CPPFLAGS $_CPPDEFFLAGS $_FORTRANMODFLAG $_FORTRANINCFLAGS /compile_only ${SOURCES.windows} /object:${TARGET.windows}' + env['OBJSUFFIX'] = '.obj' + env['FORTRANMODDIR'] = '${TARGET.dir}' + env['FORTRANMODDIRPREFIX'] = '/module:' + env['FORTRANMODDIRSUFFIX'] = '' + +def exists(env): + return env.Detect(compilers) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/cxx.py b/tools/scons/scons-local-3.0.5/SCons/Tool/cxx.py new file mode 100755 index 0000000000..85fb2fbd86 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/cxx.py @@ -0,0 +1,100 @@ +"""SCons.Tool.c++ + +Tool-specific initialization for generic Posix C++ compilers. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/cxx.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os.path + +import SCons.Tool +import SCons.Defaults +import SCons.Util + +compilers = ['CC', 'c++'] + +CXXSuffixes = ['.cpp', '.cc', '.cxx', '.c++', '.C++', '.mm'] +if SCons.Util.case_sensitive_suffixes('.c', '.C'): + CXXSuffixes.append('.C') + +def iscplusplus(source): + if not source: + # Source might be None for unusual cases like SConf. + return 0 + for s in source: + if s.sources: + ext = os.path.splitext(str(s.sources[0]))[1] + if ext in CXXSuffixes: + return 1 + return 0 + +def generate(env): + """ + Add Builders and construction variables for Visual Age C++ compilers + to an Environment. + """ + import SCons.Tool + import SCons.Tool.cc + static_obj, shared_obj = SCons.Tool.createObjBuilders(env) + + for suffix in CXXSuffixes: + static_obj.add_action(suffix, SCons.Defaults.CXXAction) + shared_obj.add_action(suffix, SCons.Defaults.ShCXXAction) + static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter) + shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter) + + SCons.Tool.cc.add_common_cc_variables(env) + + if 'CXX' not in env: + env['CXX'] = env.Detect(compilers) or compilers[0] + env['CXXFLAGS'] = SCons.Util.CLVar('') + env['CXXCOM'] = '$CXX -o $TARGET -c $CXXFLAGS $CCFLAGS $_CCCOMCOM $SOURCES' + env['SHCXX'] = '$CXX' + env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS') + env['SHCXXCOM'] = '$SHCXX -o $TARGET -c $SHCXXFLAGS $SHCCFLAGS $_CCCOMCOM $SOURCES' + + env['CPPDEFPREFIX'] = '-D' + env['CPPDEFSUFFIX'] = '' + env['INCPREFIX'] = '-I' + env['INCSUFFIX'] = '' + env['SHOBJSUFFIX'] = '.os' + env['OBJSUFFIX'] = '.o' + env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 0 + + env['CXXFILESUFFIX'] = '.cc' + +def exists(env): + return env.Detect(env.get('CXX', compilers)) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/cyglink.py b/tools/scons/scons-local-3.0.5/SCons/Tool/cyglink.py new file mode 100755 index 0000000000..f69b886dd8 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/cyglink.py @@ -0,0 +1,236 @@ +"""SCons.Tool.cyglink + +Customization of gnulink for Cygwin (http://www.cygwin.com/) + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +from __future__ import absolute_import, print_function + +import re +import os + +import SCons.Action +import SCons.Util +import SCons.Tool + +#MAYBE: from . import gnulink +from . import gnulink +from . import link + +def _lib_generator(target, source, env, for_signature, **kw): + try: cmd = kw['cmd'] + except KeyError: cmd = SCons.Util.CLVar(['$SHLINK']) + + try: vp = kw['varprefix'] + except KeyError: vp = 'SHLIB' + + dll = env.FindIxes(target, '%sPREFIX' % vp, '%sSUFFIX' % vp) + if dll: cmd.extend(['-o', dll]) + + cmd.extend(['$SHLINKFLAGS', '$__%sVERSIONFLAGS' % vp, '$__RPATH']) + + implib = env.FindIxes(target, 'IMPLIBPREFIX', 'IMPLIBSUFFIX') + if implib: + cmd.extend([ + '-Wl,--out-implib='+implib.get_string(for_signature), + '-Wl,--export-all-symbols', + '-Wl,--enable-auto-import', + '-Wl,--whole-archive', '$SOURCES', + '-Wl,--no-whole-archive', '$_LIBDIRFLAGS', '$_LIBFLAGS' + ]) + else: + cmd.extend(['$SOURCES', '$_LIBDIRFLAGS', '$_LIBFLAGS']) + + return [cmd] + + +def shlib_generator(target, source, env, for_signature): + return _lib_generator(target, source, env, for_signature, + varprefix='SHLIB', + cmd = SCons.Util.CLVar(['$SHLINK'])) + +def ldmod_generator(target, source, env, for_signature): + return _lib_generator(target, source, env, for_signature, + varprefix='LDMODULE', + cmd = SCons.Util.CLVar(['$LDMODULE'])) + +def _lib_emitter(target, source, env, **kw): + Verbose = False + + if Verbose: + print("_lib_emitter: target[0]=%r" % target[0].get_path()) + + try: vp = kw['varprefix'] + except KeyError: vp = 'SHLIB' + + try: libtype = kw['libtype'] + except KeyError: libtype = 'ShLib' + + dll = env.FindIxes(target, '%sPREFIX' % vp, '%sSUFFIX' % vp) + no_import_lib = env.get('no_import_lib', 0) + + if Verbose: + print("_lib_emitter: dll=%r" % dll.get_path()) + + if not dll or len(target) > 1: + raise SCons.Errors.UserError("A shared library should have exactly one target with the suffix: %s" % env.subst("$%sSUFFIX" % vp)) + + # Remove any "lib" after the prefix + pre = env.subst('$%sPREFIX' % vp) + if dll.name[len(pre):len(pre)+3] == 'lib': + dll.name = pre + dll.name[len(pre)+3:] + + if Verbose: + print("_lib_emitter: dll.name=%r" % dll.name) + + orig_target = target + target = [env.fs.File(dll)] + target[0].attributes.shared = 1 + + if Verbose: + print("_lib_emitter: after target=[env.fs.File(dll)]: target[0]=%r" % target[0].get_path()) + + # Append an import lib target + if not no_import_lib: + # Create list of target libraries as strings + target_strings = env.ReplaceIxes(orig_target[0], + '%sPREFIX' % vp, '%sSUFFIX' % vp, + 'IMPLIBPREFIX', 'IMPLIBSUFFIX') + if Verbose: + print("_lib_emitter: target_strings=%r" % target_strings) + + implib_target = env.fs.File(target_strings) + if Verbose: + print("_lib_emitter: implib_target=%r" % implib_target.get_path()) + implib_target.attributes.shared = 1 + target.append(implib_target) + + symlinks = SCons.Tool.ImpLibSymlinkGenerator(env, implib_target, + implib_libtype=libtype, + generator_libtype=libtype+'ImpLib') + if Verbose: + print("_lib_emitter: implib symlinks=%r" % SCons.Tool.StringizeLibSymlinks(symlinks)) + if symlinks: + SCons.Tool.EmitLibSymlinks(env, symlinks, implib_target, clean_targets = target[0]) + implib_target.attributes.shliblinks = symlinks + + return (target, source) + +def shlib_emitter(target, source, env): + return _lib_emitter(target, source, env, varprefix='SHLIB', libtype='ShLib') + +def ldmod_emitter(target, source, env): + return _lib_emitter(target, source, env, varprefix='LDMODULE', libtype='LdMod') + +def _versioned_lib_suffix(env, suffix, version): + """Generate versioned shared library suffix from a unversioned one. + If suffix='.dll', and version='0.1.2', then it returns '-0-1-2.dll'""" + Verbose = False + if Verbose: + print("_versioned_lib_suffix: suffix= ", suffix) + print("_versioned_lib_suffix: version= ", version) + cygversion = re.sub('\.', '-', version) + if not suffix.startswith('-' + cygversion): + suffix = '-' + cygversion + suffix + if Verbose: + print("_versioned_lib_suffix: return suffix= ", suffix) + return suffix + +def _versioned_implib_name(env, libnode, version, prefix, suffix, **kw): + return link._versioned_lib_name(env, libnode, version, prefix, suffix, + SCons.Tool.ImpLibPrefixGenerator, + SCons.Tool.ImpLibSuffixGenerator, + implib_libtype=kw['libtype']) + +def _versioned_implib_symlinks(env, libnode, version, prefix, suffix, **kw): + """Generate link names that should be created for a versioned shared library. + Returns a list in the form [ (link, linktarget), ... ] + """ + Verbose = False + + if Verbose: + print("_versioned_implib_symlinks: libnode=%r" % libnode.get_path()) + print("_versioned_implib_symlinks: version=%r" % version) + + try: libtype = kw['libtype'] + except KeyError: libtype = 'ShLib' + + + linkdir = os.path.dirname(libnode.get_path()) + if Verbose: + print("_versioned_implib_symlinks: linkdir=%r" % linkdir) + + name = SCons.Tool.ImpLibNameGenerator(env, libnode, + implib_libtype=libtype, + generator_libtype=libtype+'ImpLib') + if Verbose: + print("_versioned_implib_symlinks: name=%r" % name) + + major = version.split('.')[0] + + link0 = env.fs.File(os.path.join(linkdir, name)) + symlinks = [(link0, libnode)] + + if Verbose: + print("_versioned_implib_symlinks: return symlinks=%r" % SCons.Tool.StringizeLibSymlinks(symlinks)) + + return symlinks + +shlib_action = SCons.Action.Action(shlib_generator, generator=1) +ldmod_action = SCons.Action.Action(ldmod_generator, generator=1) + +def generate(env): + """Add Builders and construction variables for cyglink to an Environment.""" + gnulink.generate(env) + + env['LINKFLAGS'] = SCons.Util.CLVar('-Wl,-no-undefined') + + env['SHLINKCOM'] = shlib_action + env['LDMODULECOM'] = ldmod_action + env.Append(SHLIBEMITTER = [shlib_emitter]) + env.Append(LDMODULEEMITTER = [ldmod_emitter]) + + env['SHLIBPREFIX'] = 'cyg' + env['SHLIBSUFFIX'] = '.dll' + + env['IMPLIBPREFIX'] = 'lib' + env['IMPLIBSUFFIX'] = '.dll.a' + + # Variables used by versioned shared libraries + env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS' + env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS' + + # SHLIBVERSIONFLAGS and LDMODULEVERSIONFLAGS are same as in gnulink... + + # LINKCALLBACKS are NOT inherited from gnulink + env['LINKCALLBACKS'] = { + 'VersionedShLibSuffix' : _versioned_lib_suffix, + 'VersionedLdModSuffix' : _versioned_lib_suffix, + 'VersionedImpLibSuffix' : _versioned_lib_suffix, + 'VersionedShLibName' : link._versioned_shlib_name, + 'VersionedLdModName' : link._versioned_ldmod_name, + 'VersionedShLibImpLibName' : lambda *args: _versioned_implib_name(*args, libtype='ShLib'), + 'VersionedLdModImpLibName' : lambda *args: _versioned_implib_name(*args, libtype='LdMod'), + 'VersionedShLibImpLibSymlinks' : lambda *args: _versioned_implib_symlinks(*args, libtype='ShLib'), + 'VersionedLdModImpLibSymlinks' : lambda *args: _versioned_implib_symlinks(*args, libtype='LdMod'), + } + + # these variables were set by gnulink but are not used in cyglink + try: del env['_SHLIBSONAME'] + except KeyError: pass + try: del env['_LDMODULESONAME'] + except KeyError: pass + +def exists(env): + return gnulink.exists(env) + + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/default.py b/tools/scons/scons-local-3.0.5/SCons/Tool/default.py new file mode 100755 index 0000000000..928e365abe --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/default.py @@ -0,0 +1,50 @@ +"""SCons.Tool.default + +Initialization with a default tool list. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/default.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Tool + +def generate(env): + """Add default tools.""" + for t in SCons.Tool.tool_list(env['PLATFORM'], env): + SCons.Tool.Tool(t)(env) + +def exists(env): + return 1 + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/dmd.py b/tools/scons/scons-local-3.0.5/SCons/Tool/dmd.py new file mode 100755 index 0000000000..d9bed9c40d --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/dmd.py @@ -0,0 +1,161 @@ +from __future__ import print_function + +"""SCons.Tool.dmd + +Tool-specific initialization for the Digital Mars D compiler. +(http://digitalmars.com/d) + +Originally coded by Andy Friesen (andy@ikagames.com) +15 November 2003 + +Evolved by Russel Winder (russel@winder.org.uk) +2010-02-07 onwards + +Compiler variables: + DC - The name of the D compiler to use. Defaults to dmd or gdmd, + whichever is found. + DPATH - List of paths to search for import modules. + DVERSIONS - List of version tags to enable when compiling. + DDEBUG - List of debug tags to enable when compiling. + +Linker related variables: + LIBS - List of library files to link in. + DLINK - Name of the linker to use. Defaults to dmd or gdmd, + whichever is found. + DLINKFLAGS - List of linker flags. + +Lib tool variables: + DLIB - Name of the lib tool to use. Defaults to lib. + DLIBFLAGS - List of flags to pass to the lib tool. + LIBS - Same as for the linker. (libraries to pull into the .lib) +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/dmd.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os +import subprocess + +import SCons.Action +import SCons.Builder +import SCons.Defaults +import SCons.Scanner.D +import SCons.Tool + +import SCons.Tool.DCommon as DCommon + + +def generate(env): + static_obj, shared_obj = SCons.Tool.createObjBuilders(env) + + static_obj.add_action('.d', SCons.Defaults.DAction) + shared_obj.add_action('.d', SCons.Defaults.ShDAction) + static_obj.add_emitter('.d', SCons.Defaults.StaticObjectEmitter) + shared_obj.add_emitter('.d', SCons.Defaults.SharedObjectEmitter) + + env['DC'] = env.Detect(['dmd', 'ldmd2', 'gdmd']) or 'dmd' + env['DCOM'] = '$DC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -c -of$TARGET $SOURCES' + env['_DINCFLAGS'] = '${_concat(DINCPREFIX, DPATH, DINCSUFFIX, __env__, RDirs, TARGET, SOURCE)}' + env['_DVERFLAGS'] = '${_concat(DVERPREFIX, DVERSIONS, DVERSUFFIX, __env__)}' + env['_DDEBUGFLAGS'] = '${_concat(DDEBUGPREFIX, DDEBUG, DDEBUGSUFFIX, __env__)}' + env['_DFLAGS'] = '${_concat(DFLAGPREFIX, DFLAGS, DFLAGSUFFIX, __env__)}' + + env['SHDC'] = '$DC' + env['SHDCOM'] = '$DC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -c -fPIC -of$TARGET $SOURCES' + + env['DPATH'] = ['#/'] + env['DFLAGS'] = [] + env['DVERSIONS'] = [] + env['DDEBUG'] = [] + + if env['DC']: + DCommon.addDPATHToEnv(env, env['DC']) + + env['DINCPREFIX'] = '-I' + env['DINCSUFFIX'] = '' + env['DVERPREFIX'] = '-version=' + env['DVERSUFFIX'] = '' + env['DDEBUGPREFIX'] = '-debug=' + env['DDEBUGSUFFIX'] = '' + env['DFLAGPREFIX'] = '-' + env['DFLAGSUFFIX'] = '' + env['DFILESUFFIX'] = '.d' + + env['DLINK'] = '$DC' + env['DLINKFLAGS'] = SCons.Util.CLVar('') + env['DLINKCOM'] = '$DLINK -of$TARGET $DLINKFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS' + + env['SHDLINK'] = '$DC' + env['SHDLINKFLAGS'] = SCons.Util.CLVar('$DLINKFLAGS -shared -defaultlib=libphobos2.so') + env['SHDLINKCOM'] = '$DLINK -of$TARGET $SHDLINKFLAGS $__SHDLIBVERSIONFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS' + + env['DLIBLINKPREFIX'] = '' if env['PLATFORM'] == 'win32' else '-L-l' + env['DLIBLINKSUFFIX'] = '.lib' if env['PLATFORM'] == 'win32' else '' + env['_DLIBFLAGS'] = '${_stripixes(DLIBLINKPREFIX, LIBS, DLIBLINKSUFFIX, LIBPREFIXES, LIBSUFFIXES, __env__)}' + + env['DLIBDIRPREFIX'] = '-L-L' + env['DLIBDIRSUFFIX'] = '' + env['_DLIBDIRFLAGS'] = '${_concat(DLIBDIRPREFIX, LIBPATH, DLIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)}' + + env['DLIB'] = 'lib' if env['PLATFORM'] == 'win32' else 'ar cr' + env['DLIBCOM'] = '$DLIB $_DLIBFLAGS {0}$TARGET $SOURCES $_DLIBFLAGS'.format('-c ' if env['PLATFORM'] == 'win32' else '') + + # env['_DLIBFLAGS'] = '${_concat(DLIBFLAGPREFIX, DLIBFLAGS, DLIBFLAGSUFFIX, __env__)}' + + env['DLIBFLAGPREFIX'] = '-' + env['DLIBFLAGSUFFIX'] = '' + + # __RPATH is set to $_RPATH in the platform specification if that + # platform supports it. + env['DRPATHPREFIX'] = '-L-rpath,' if env['PLATFORM'] == 'darwin' else '-L-rpath=' + env['DRPATHSUFFIX'] = '' + env['_DRPATH'] = '${_concat(DRPATHPREFIX, RPATH, DRPATHSUFFIX, __env__)}' + + # Support for versioned libraries + env['_SHDLIBVERSIONFLAGS'] = '$SHDLIBVERSIONFLAGS -L-soname=$_SHDLIBSONAME' + env['_SHDLIBSONAME'] = '${DShLibSonameGenerator(__env__,TARGET)}' + # NOTE: this is a quick hack, the soname will only work if there is + # c/c++ linker loaded which provides callback for the ShLibSonameGenerator + env['DShLibSonameGenerator'] = SCons.Tool.ShLibSonameGenerator + # NOTE: this is only for further reference, currently $SHDLIBVERSION does + # not work, the user must use $SHLIBVERSION + env['SHDLIBVERSION'] = '$SHLIBVERSION' + env['SHDLIBVERSIONFLAGS'] = [] + + env['BUILDERS']['ProgramAllAtOnce'] = SCons.Builder.Builder( + action='$DC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -of$TARGET $DLINKFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS', + emitter=DCommon.allAtOnceEmitter, + ) + + +def exists(env): + return env.Detect(['dmd', 'ldmd2', 'gdmd']) + + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/docbook/__init__.py b/tools/scons/scons-local-3.0.5/SCons/Tool/docbook/__init__.py new file mode 100755 index 0000000000..d7d10c00fc --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/docbook/__init__.py @@ -0,0 +1,885 @@ + +"""SCons.Tool.docbook + +Tool-specific initialization for Docbook. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +import os +import glob +import re + +import SCons.Action +import SCons.Builder +import SCons.Defaults +import SCons.Script +import SCons.Tool +import SCons.Util + + +__debug_tool_location = False +# Get full path to this script +scriptpath = os.path.dirname(os.path.realpath(__file__)) + +# Local folder for the collection of DocBook XSLs +db_xsl_folder = 'docbook-xsl-1.76.1' + +# Do we have libxml2/libxslt/lxml? +has_libxml2 = True +has_lxml = True +try: + import libxml2 + import libxslt +except: + has_libxml2 = False +try: + import lxml +except: + has_lxml = False + +# Set this to True, to prefer xsltproc over libxml2 and lxml +prefer_xsltproc = False + +# Regexs for parsing Docbook XML sources of MAN pages +re_manvolnum = re.compile("([^<]*)") +re_refname = re.compile("([^<]*)") + +# +# Helper functions +# +def __extend_targets_sources(target, source): + """ Prepare the lists of target and source files. """ + if not SCons.Util.is_List(target): + target = [target] + if not source: + source = target[:] + elif not SCons.Util.is_List(source): + source = [source] + if len(target) < len(source): + target.extend(source[len(target):]) + + return target, source + +def __init_xsl_stylesheet(kw, env, user_xsl_var, default_path): + if kw.get('DOCBOOK_XSL','') == '': + xsl_style = kw.get('xsl', env.subst(user_xsl_var)) + if xsl_style == '': + path_args = [scriptpath, db_xsl_folder] + default_path + xsl_style = os.path.join(*path_args) + kw['DOCBOOK_XSL'] = xsl_style + +def __select_builder(lxml_builder, libxml2_builder, cmdline_builder): + """ Selects a builder, based on which Python modules are present. """ + if prefer_xsltproc: + return cmdline_builder + + if not has_libxml2: + # At the moment we prefer libxml2 over lxml, the latter can lead + # to conflicts when installed together with libxml2. + if has_lxml: + return lxml_builder + else: + return cmdline_builder + + return libxml2_builder + +def __ensure_suffix(t, suffix): + """ Ensure that the target t has the given suffix. """ + tpath = str(t) + if not tpath.endswith(suffix): + return tpath+suffix + + return t + +def __ensure_suffix_stem(t, suffix): + """ Ensure that the target t has the given suffix, and return the file's stem. """ + tpath = str(t) + if not tpath.endswith(suffix): + stem = tpath + tpath += suffix + + return tpath, stem + else: + stem, ext = os.path.splitext(tpath) + + return t, stem + +def __get_xml_text(root): + """ Return the text for the given root node (xml.dom.minidom). """ + txt = "" + for e in root.childNodes: + if (e.nodeType == e.TEXT_NODE): + txt += e.data + return txt + +def __create_output_dir(base_dir): + """ Ensure that the output directory base_dir exists. """ + root, tail = os.path.split(base_dir) + dir = None + if tail: + if base_dir.endswith('/'): + dir = base_dir + else: + dir = root + else: + if base_dir.endswith('/'): + dir = base_dir + + if dir and not os.path.isdir(dir): + os.makedirs(dir) + + +# +# Supported command line tools and their call "signature" +# +xsltproc_com_priority = ['xsltproc', 'saxon', 'saxon-xslt', 'xalan'] + +# TODO: Set minimum version of saxon-xslt to be 8.x (lower than this only supports xslt 1.0. +# see: http://saxon.sourceforge.net/saxon6.5.5/ +# see: http://saxon.sourceforge.net/ +xsltproc_com = {'xsltproc' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $DOCBOOK_XSL $SOURCE', + 'saxon' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $DOCBOOK_XSL $SOURCE $DOCBOOK_XSLTPROCPARAMS', + # Note if saxon-xslt is version 5.5 the proper arguments are: (swap order of docbook_xsl and source) + # 'saxon-xslt' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $SOURCE $DOCBOOK_XSL $DOCBOOK_XSLTPROCPARAMS', + 'saxon-xslt' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $DOCBOOK_XSL $SOURCE $DOCBOOK_XSLTPROCPARAMS', + 'xalan' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -q -out $TARGET -xsl $DOCBOOK_XSL -in $SOURCE'} +xmllint_com = {'xmllint' : '$DOCBOOK_XMLLINT $DOCBOOK_XMLLINTFLAGS --xinclude $SOURCE > $TARGET'} +fop_com = {'fop' : '$DOCBOOK_FOP $DOCBOOK_FOPFLAGS -fo $SOURCE -pdf $TARGET', + 'xep' : '$DOCBOOK_FOP $DOCBOOK_FOPFLAGS -valid -fo $SOURCE -pdf $TARGET', + 'jw' : '$DOCBOOK_FOP $DOCBOOK_FOPFLAGS -f docbook -b pdf $SOURCE -o $TARGET'} + +def __detect_cl_tool(env, chainkey, cdict, cpriority=None): + """ + Helper function, picks a command line tool from the list + and initializes its environment variables. + """ + if env.get(chainkey,'') == '': + clpath = '' + + if cpriority is None: + cpriority = cdict.keys() + for cltool in cpriority: + if __debug_tool_location: + print("DocBook: Looking for %s"%cltool) + clpath = env.WhereIs(cltool) + if clpath: + if __debug_tool_location: + print("DocBook: Found:%s"%cltool) + env[chainkey] = clpath + if not env[chainkey + 'COM']: + env[chainkey + 'COM'] = cdict[cltool] + break + +def _detect(env): + """ + Detect all the command line tools that we might need for creating + the requested output formats. + """ + global prefer_xsltproc + + if env.get('DOCBOOK_PREFER_XSLTPROC',''): + prefer_xsltproc = True + + if ((not has_libxml2 and not has_lxml) or (prefer_xsltproc)): + # Try to find the XSLT processors + __detect_cl_tool(env, 'DOCBOOK_XSLTPROC', xsltproc_com, xsltproc_com_priority) + __detect_cl_tool(env, 'DOCBOOK_XMLLINT', xmllint_com) + + __detect_cl_tool(env, 'DOCBOOK_FOP', fop_com, ['fop','xep','jw']) + +# +# Scanners +# +include_re = re.compile('fileref\\s*=\\s*["|\']([^\\n]*)["|\']') +sentity_re = re.compile('') + +def __xml_scan(node, env, path, arg): + """ Simple XML file scanner, detecting local images and XIncludes as implicit dependencies. """ + # Does the node exist yet? + if not os.path.isfile(str(node)): + return [] + + if env.get('DOCBOOK_SCANENT',''): + # Use simple pattern matching for system entities..., no support + # for recursion yet. + contents = node.get_text_contents() + return sentity_re.findall(contents) + + xsl_file = os.path.join(scriptpath,'utils','xmldepend.xsl') + if not has_libxml2 or prefer_xsltproc: + if has_lxml and not prefer_xsltproc: + + from lxml import etree + + xsl_tree = etree.parse(xsl_file) + doc = etree.parse(str(node)) + result = doc.xslt(xsl_tree) + + depfiles = [x.strip() for x in str(result).splitlines() if x.strip() != "" and not x.startswith(" 1: + env.Clean(outfiles[0], outfiles[1:]) + + + return result + +def DocbookSlidesPdf(env, target, source=None, *args, **kw): + """ + A pseudo-Builder, providing a Docbook toolchain for PDF slides output. + """ + # Init list of targets/sources + target, source = __extend_targets_sources(target, source) + + # Init XSL stylesheet + __init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_SLIDESPDF', ['slides','fo','plain.xsl']) + + # Setup builder + __builder = __select_builder(__lxml_builder, __libxml2_builder, __xsltproc_builder) + + # Create targets + result = [] + for t,s in zip(target,source): + t, stem = __ensure_suffix_stem(t, '.pdf') + xsl = __builder.__call__(env, stem+'.fo', s, **kw) + env.Depends(xsl, kw['DOCBOOK_XSL']) + result.extend(xsl) + result.extend(__fop_builder.__call__(env, t, xsl, **kw)) + + return result + +def DocbookSlidesHtml(env, target, source=None, *args, **kw): + """ + A pseudo-Builder, providing a Docbook toolchain for HTML slides output. + """ + # Init list of targets/sources + if not SCons.Util.is_List(target): + target = [target] + if not source: + source = target + target = ['index.html'] + elif not SCons.Util.is_List(source): + source = [source] + + # Init XSL stylesheet + __init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_SLIDESHTML', ['slides','html','plain.xsl']) + + # Setup builder + __builder = __select_builder(__lxml_builder, __libxml2_builder, __xsltproc_builder) + + # Detect base dir + base_dir = kw.get('base_dir', '') + if base_dir: + __create_output_dir(base_dir) + + # Create targets + result = [] + r = __builder.__call__(env, __ensure_suffix(str(target[0]), '.html'), source[0], **kw) + env.Depends(r, kw['DOCBOOK_XSL']) + result.extend(r) + # Add supporting files for cleanup + env.Clean(r, [os.path.join(base_dir, 'toc.html')] + + glob.glob(os.path.join(base_dir, 'foil*.html'))) + + return result + +def DocbookXInclude(env, target, source, *args, **kw): + """ + A pseudo-Builder, for resolving XIncludes in a separate processing step. + """ + # Init list of targets/sources + target, source = __extend_targets_sources(target, source) + + # Setup builder + __builder = __select_builder(__xinclude_lxml_builder,__xinclude_libxml2_builder,__xmllint_builder) + + # Create targets + result = [] + for t,s in zip(target,source): + result.extend(__builder.__call__(env, t, s, **kw)) + + return result + +def DocbookXslt(env, target, source=None, *args, **kw): + """ + A pseudo-Builder, applying a simple XSL transformation to the input file. + """ + # Init list of targets/sources + target, source = __extend_targets_sources(target, source) + + # Init XSL stylesheet + kw['DOCBOOK_XSL'] = kw.get('xsl', 'transform.xsl') + + # Setup builder + __builder = __select_builder(__lxml_builder, __libxml2_builder, __xsltproc_builder) + + # Create targets + result = [] + for t,s in zip(target,source): + r = __builder.__call__(env, t, s, **kw) + env.Depends(r, kw['DOCBOOK_XSL']) + result.extend(r) + + return result + + +def generate(env): + """Add Builders and construction variables for docbook to an Environment.""" + + env.SetDefault( + # Default names for customized XSL stylesheets + DOCBOOK_DEFAULT_XSL_EPUB = '', + DOCBOOK_DEFAULT_XSL_HTML = '', + DOCBOOK_DEFAULT_XSL_HTMLCHUNKED = '', + DOCBOOK_DEFAULT_XSL_HTMLHELP = '', + DOCBOOK_DEFAULT_XSL_PDF = '', + DOCBOOK_DEFAULT_XSL_MAN = '', + DOCBOOK_DEFAULT_XSL_SLIDESPDF = '', + DOCBOOK_DEFAULT_XSL_SLIDESHTML = '', + + # Paths to the detected executables + DOCBOOK_XSLTPROC = '', + DOCBOOK_XMLLINT = '', + DOCBOOK_FOP = '', + + # Additional flags for the text processors + DOCBOOK_XSLTPROCFLAGS = SCons.Util.CLVar(''), + DOCBOOK_XMLLINTFLAGS = SCons.Util.CLVar(''), + DOCBOOK_FOPFLAGS = SCons.Util.CLVar(''), + DOCBOOK_XSLTPROCPARAMS = SCons.Util.CLVar(''), + + # Default command lines for the detected executables + DOCBOOK_XSLTPROCCOM = xsltproc_com['xsltproc'], + DOCBOOK_XMLLINTCOM = xmllint_com['xmllint'], + DOCBOOK_FOPCOM = fop_com['fop'], + + # Screen output for the text processors + DOCBOOK_XSLTPROCCOMSTR = None, + DOCBOOK_XMLLINTCOMSTR = None, + DOCBOOK_FOPCOMSTR = None, + + ) + _detect(env) + + env.AddMethod(DocbookEpub, "DocbookEpub") + env.AddMethod(DocbookHtml, "DocbookHtml") + env.AddMethod(DocbookHtmlChunked, "DocbookHtmlChunked") + env.AddMethod(DocbookHtmlhelp, "DocbookHtmlhelp") + env.AddMethod(DocbookPdf, "DocbookPdf") + env.AddMethod(DocbookMan, "DocbookMan") + env.AddMethod(DocbookSlidesPdf, "DocbookSlidesPdf") + env.AddMethod(DocbookSlidesHtml, "DocbookSlidesHtml") + env.AddMethod(DocbookXInclude, "DocbookXInclude") + env.AddMethod(DocbookXslt, "DocbookXslt") + + +def exists(env): + return 1 diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/dvi.py b/tools/scons/scons-local-3.0.5/SCons/Tool/dvi.py new file mode 100755 index 0000000000..7fbca27227 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/dvi.py @@ -0,0 +1,64 @@ +"""SCons.Tool.dvi + +Common DVI Builder definition for various other Tool modules that use it. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/dvi.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Builder +import SCons.Tool + +DVIBuilder = None + +def generate(env): + try: + env['BUILDERS']['DVI'] + except KeyError: + global DVIBuilder + + if DVIBuilder is None: + # The suffix is hard-coded to '.dvi', not configurable via a + # construction variable like $DVISUFFIX, because the output + # file name is hard-coded within TeX. + DVIBuilder = SCons.Builder.Builder(action = {}, + source_scanner = SCons.Tool.LaTeXScanner, + suffix = '.dvi', + emitter = {}, + source_ext_match = None) + + env['BUILDERS']['DVI'] = DVIBuilder + +def exists(env): + # This only puts a skeleton Builder in place, so if someone + # references this Tool directly, it's always "available." + return 1 + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/dvipdf.py b/tools/scons/scons-local-3.0.5/SCons/Tool/dvipdf.py new file mode 100755 index 0000000000..340929ef38 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/dvipdf.py @@ -0,0 +1,125 @@ +"""SCons.Tool.dvipdf + +Tool-specific initialization for dvipdf. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +__revision__ = "src/engine/SCons/Tool/dvipdf.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Action +import SCons.Defaults +import SCons.Tool.pdf +import SCons.Tool.tex +import SCons.Util + +_null = SCons.Scanner.LaTeX._null + +def DviPdfPsFunction(XXXDviAction, target = None, source= None, env=None): + """A builder for DVI files that sets the TEXPICTS environment + variable before running dvi2ps or dvipdf.""" + + try: + abspath = source[0].attributes.path + except AttributeError : + abspath = '' + + saved_env = SCons.Scanner.LaTeX.modify_env_var(env, 'TEXPICTS', abspath) + + result = XXXDviAction(target, source, env) + + if saved_env is _null: + try: + del env['ENV']['TEXPICTS'] + except KeyError: + pass # was never set + else: + env['ENV']['TEXPICTS'] = saved_env + + return result + +def DviPdfFunction(target = None, source= None, env=None): + result = DviPdfPsFunction(PDFAction,target,source,env) + return result + +def DviPdfStrFunction(target = None, source= None, env=None): + """A strfunction for dvipdf that returns the appropriate + command string for the no_exec options.""" + if env.GetOption("no_exec"): + result = env.subst('$DVIPDFCOM',0,target,source) + else: + result = '' + return result + +PDFAction = None +DVIPDFAction = None + +def PDFEmitter(target, source, env): + """Strips any .aux or .log files from the input source list. + These are created by the TeX Builder that in all likelihood was + used to generate the .dvi file we're using as input, and we only + care about the .dvi file. + """ + def strip_suffixes(n): + return not SCons.Util.splitext(str(n))[1] in ['.aux', '.log'] + source = [src for src in source if strip_suffixes(src)] + return (target, source) + +def generate(env): + """Add Builders and construction variables for dvipdf to an Environment.""" + global PDFAction + if PDFAction is None: + PDFAction = SCons.Action.Action('$DVIPDFCOM', '$DVIPDFCOMSTR') + + global DVIPDFAction + if DVIPDFAction is None: + DVIPDFAction = SCons.Action.Action(DviPdfFunction, strfunction = DviPdfStrFunction) + + from . import pdf + pdf.generate(env) + + bld = env['BUILDERS']['PDF'] + bld.add_action('.dvi', DVIPDFAction) + bld.add_emitter('.dvi', PDFEmitter) + + env['DVIPDF'] = 'dvipdf' + env['DVIPDFFLAGS'] = SCons.Util.CLVar('') + env['DVIPDFCOM'] = 'cd ${TARGET.dir} && $DVIPDF $DVIPDFFLAGS ${SOURCE.file} ${TARGET.file}' + + # Deprecated synonym. + env['PDFCOM'] = ['$DVIPDFCOM'] + +def exists(env): + SCons.Tool.tex.generate_darwin(env) + return env.Detect('dvipdf') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/dvips.py b/tools/scons/scons-local-3.0.5/SCons/Tool/dvips.py new file mode 100755 index 0000000000..16d409d3a5 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/dvips.py @@ -0,0 +1,95 @@ +"""SCons.Tool.dvips + +Tool-specific initialization for dvips. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/dvips.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Action +import SCons.Builder +import SCons.Tool.dvipdf +import SCons.Util + +def DviPsFunction(target = None, source= None, env=None): + result = SCons.Tool.dvipdf.DviPdfPsFunction(PSAction,target,source,env) + return result + +def DviPsStrFunction(target = None, source= None, env=None): + """A strfunction for dvipdf that returns the appropriate + command string for the no_exec options.""" + if env.GetOption("no_exec"): + result = env.subst('$PSCOM',0,target,source) + else: + result = '' + return result + +PSAction = None +DVIPSAction = None +PSBuilder = None + +def generate(env): + """Add Builders and construction variables for dvips to an Environment.""" + global PSAction + if PSAction is None: + PSAction = SCons.Action.Action('$PSCOM', '$PSCOMSTR') + + global DVIPSAction + if DVIPSAction is None: + DVIPSAction = SCons.Action.Action(DviPsFunction, strfunction = DviPsStrFunction) + + global PSBuilder + if PSBuilder is None: + PSBuilder = SCons.Builder.Builder(action = PSAction, + prefix = '$PSPREFIX', + suffix = '$PSSUFFIX', + src_suffix = '.dvi', + src_builder = 'DVI', + single_source=True) + + env['BUILDERS']['PostScript'] = PSBuilder + + env['DVIPS'] = 'dvips' + env['DVIPSFLAGS'] = SCons.Util.CLVar('') + # I'm not quite sure I got the directories and filenames right for variant_dir + # We need to be in the correct directory for the sake of latex \includegraphics eps included files. + env['PSCOM'] = 'cd ${TARGET.dir} && $DVIPS $DVIPSFLAGS -o ${TARGET.file} ${SOURCE.file}' + env['PSPREFIX'] = '' + env['PSSUFFIX'] = '.ps' + +def exists(env): + SCons.Tool.tex.generate_darwin(env) + return env.Detect('dvips') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/f03.py b/tools/scons/scons-local-3.0.5/SCons/Tool/f03.py new file mode 100755 index 0000000000..dddc650d93 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/f03.py @@ -0,0 +1,63 @@ +"""engine.SCons.Tool.f03 + +Tool-specific initialization for the generic Posix f03 Fortran compiler. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/f03.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Defaults +import SCons.Tool +import SCons.Util +from . import fortran +from SCons.Tool.FortranCommon import add_all_to_env, add_f03_to_env + +compilers = ['f03'] + +def generate(env): + add_all_to_env(env) + add_f03_to_env(env) + + fcomp = env.Detect(compilers) or 'f03' + env['F03'] = fcomp + env['SHF03'] = fcomp + + env['FORTRAN'] = fcomp + env['SHFORTRAN'] = fcomp + + +def exists(env): + return env.Detect(compilers) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/f08.py b/tools/scons/scons-local-3.0.5/SCons/Tool/f08.py new file mode 100755 index 0000000000..c5209e4121 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/f08.py @@ -0,0 +1,65 @@ +"""engine.SCons.Tool.f08 + +Tool-specific initialization for the generic Posix f08 Fortran compiler. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +from __future__ import absolute_import + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/f08.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Defaults +import SCons.Tool +import SCons.Util +from . import fortran +from SCons.Tool.FortranCommon import add_all_to_env, add_f08_to_env + +compilers = ['f08'] + +def generate(env): + add_all_to_env(env) + add_f08_to_env(env) + + fcomp = env.Detect(compilers) or 'f08' + env['F08'] = fcomp + env['SHF08'] = fcomp + + env['FORTRAN'] = fcomp + env['SHFORTRAN'] = fcomp + + +def exists(env): + return env.Detect(compilers) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/f77.py b/tools/scons/scons-local-3.0.5/SCons/Tool/f77.py new file mode 100755 index 0000000000..2665867bda --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/f77.py @@ -0,0 +1,62 @@ +"""engine.SCons.Tool.f77 + +Tool-specific initialization for the generic Posix f77 Fortran compiler. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/f77.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Defaults +import SCons.Scanner.Fortran +import SCons.Tool +import SCons.Util +from SCons.Tool.FortranCommon import add_all_to_env, add_f77_to_env + +compilers = ['f77'] + +def generate(env): + add_all_to_env(env) + add_f77_to_env(env) + + fcomp = env.Detect(compilers) or 'f77' + env['F77'] = fcomp + env['SHF77'] = fcomp + + env['FORTRAN'] = fcomp + env['SHFORTRAN'] = fcomp + +def exists(env): + return env.Detect(compilers) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/f90.py b/tools/scons/scons-local-3.0.5/SCons/Tool/f90.py new file mode 100755 index 0000000000..a6f5cffb8f --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/f90.py @@ -0,0 +1,62 @@ +"""engine.SCons.Tool.f90 + +Tool-specific initialization for the generic Posix f90 Fortran compiler. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/f90.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Defaults +import SCons.Scanner.Fortran +import SCons.Tool +import SCons.Util +from SCons.Tool.FortranCommon import add_all_to_env, add_f90_to_env + +compilers = ['f90'] + +def generate(env): + add_all_to_env(env) + add_f90_to_env(env) + + fc = env.Detect(compilers) or 'f90' + env['F90'] = fc + env['SHF90'] = fc + + env['FORTRAN'] = fc + env['SHFORTRAN'] = fc + +def exists(env): + return env.Detect(compilers) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/f95.py b/tools/scons/scons-local-3.0.5/SCons/Tool/f95.py new file mode 100755 index 0000000000..3e611e87cc --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/f95.py @@ -0,0 +1,63 @@ +"""engine.SCons.Tool.f95 + +Tool-specific initialization for the generic Posix f95 Fortran compiler. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/f95.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Defaults +import SCons.Tool +import SCons.Util +from . import fortran +from SCons.Tool.FortranCommon import add_all_to_env, add_f95_to_env + +compilers = ['f95'] + +def generate(env): + add_all_to_env(env) + add_f95_to_env(env) + + fcomp = env.Detect(compilers) or 'f95' + env['F95'] = fcomp + env['SHF95'] = fcomp + + env['FORTRAN'] = fcomp + env['SHFORTRAN'] = fcomp + + +def exists(env): + return env.Detect(compilers) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/filesystem.py b/tools/scons/scons-local-3.0.5/SCons/Tool/filesystem.py new file mode 100755 index 0000000000..312f08c793 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/filesystem.py @@ -0,0 +1,98 @@ +"""SCons.Tool.filesystem + +Tool-specific initialization for the filesystem tools. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/filesystem.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons +from SCons.Tool.install import copyFunc + +copyToBuilder, copyAsBuilder = None, None + +def copyto_emitter(target, source, env): + """ changes the path of the source to be under the target (which + are assumed to be directories. + """ + n_target = [] + + for t in target: + n_target = n_target + [t.File( str( s ) ) for s in source] + + return (n_target, source) + +def copy_action_func(target, source, env): + assert( len(target) == len(source) ), "\ntarget: %s\nsource: %s" %(list(map(str, target)),list(map(str, source))) + + for t, s in zip(target, source): + if copyFunc(t.get_path(), s.get_path(), env): + return 1 + + return 0 + +def copy_action_str(target, source, env): + return env.subst_target_source(env['COPYSTR'], 0, target, source) + +copy_action = SCons.Action.Action( copy_action_func, copy_action_str ) + +def generate(env): + try: + env['BUILDERS']['CopyTo'] + env['BUILDERS']['CopyAs'] + except KeyError as e: + global copyToBuilder + if copyToBuilder is None: + copyToBuilder = SCons.Builder.Builder( + action = copy_action, + target_factory = env.fs.Dir, + source_factory = env.fs.Entry, + multi = 1, + emitter = [ copyto_emitter, ] ) + + global copyAsBuilder + if copyAsBuilder is None: + copyAsBuilder = SCons.Builder.Builder( + action = copy_action, + target_factory = env.fs.Entry, + source_factory = env.fs.Entry ) + + env['BUILDERS']['CopyTo'] = copyToBuilder + env['BUILDERS']['CopyAs'] = copyAsBuilder + + env['COPYSTR'] = 'Copy file(s): "$SOURCES" to "$TARGETS"' + +def exists(env): + return 1 + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/fortran.py b/tools/scons/scons-local-3.0.5/SCons/Tool/fortran.py new file mode 100755 index 0000000000..b57a84555c --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/fortran.py @@ -0,0 +1,62 @@ +"""SCons.Tool.fortran + +Tool-specific initialization for a generic Posix f77/f90 Fortran compiler. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/fortran.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import re + +import SCons.Action +import SCons.Defaults +import SCons.Scanner.Fortran +import SCons.Tool +import SCons.Util +from SCons.Tool.FortranCommon import add_all_to_env, add_fortran_to_env + +compilers = ['f95', 'f90', 'f77'] + +def generate(env): + add_all_to_env(env) + add_fortran_to_env(env) + + fc = env.Detect(compilers) or 'f77' + env['SHFORTRAN'] = fc + env['FORTRAN'] = fc + +def exists(env): + return env.Detect(compilers) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/g++.py b/tools/scons/scons-local-3.0.5/SCons/Tool/g++.py new file mode 100755 index 0000000000..b28e39d3c8 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/g++.py @@ -0,0 +1,45 @@ +"""SCons.Tool.g++ + +Tool-specific initialization for g++. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/g++.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + + +#forward proxy to the preffered cxx version +from SCons.Tool.gxx import * + + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/g77.py b/tools/scons/scons-local-3.0.5/SCons/Tool/g77.py new file mode 100755 index 0000000000..1c1f10130a --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/g77.py @@ -0,0 +1,73 @@ +"""engine.SCons.Tool.g77 + +Tool-specific initialization for g77. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/g77.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Util +from SCons.Tool.FortranCommon import add_all_to_env, add_f77_to_env + +compilers = ['g77', 'f77'] + +def generate(env): + """Add Builders and construction variables for g77 to an Environment.""" + add_all_to_env(env) + add_f77_to_env(env) + + fcomp = env.Detect(compilers) or 'g77' + if env['PLATFORM'] in ['cygwin', 'win32']: + env['SHFORTRANFLAGS'] = SCons.Util.CLVar('$FORTRANFLAGS') + env['SHF77FLAGS'] = SCons.Util.CLVar('$F77FLAGS') + else: + env['SHFORTRANFLAGS'] = SCons.Util.CLVar('$FORTRANFLAGS -fPIC') + env['SHF77FLAGS'] = SCons.Util.CLVar('$F77FLAGS -fPIC') + + env['FORTRAN'] = fcomp + env['SHFORTRAN'] = '$FORTRAN' + + env['F77'] = fcomp + env['SHF77'] = '$F77' + + env['INCFORTRANPREFIX'] = "-I" + env['INCFORTRANSUFFIX'] = "" + + env['INCF77PREFIX'] = "-I" + env['INCF77SUFFIX'] = "" + +def exists(env): + return env.Detect(compilers) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/gas.py b/tools/scons/scons-local-3.0.5/SCons/Tool/gas.py new file mode 100755 index 0000000000..5ad8a76334 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/gas.py @@ -0,0 +1,56 @@ +"""SCons.Tool.gas + +Tool-specific initialization for as, the Gnu assembler. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/gas.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +try: + as_module = __import__('as', globals(), locals(), []) +except: + as_module = __import__(__package__+'.as', globals(), locals(), ['*']) + +assemblers = ['as', 'gas'] + +def generate(env): + """Add Builders and construction variables for as to an Environment.""" + as_module.generate(env) + + env['AS'] = env.Detect(assemblers) or 'as' + +def exists(env): + return env.Detect(assemblers) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/gcc.py b/tools/scons/scons-local-3.0.5/SCons/Tool/gcc.py new file mode 100755 index 0000000000..880fc8084b --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/gcc.py @@ -0,0 +1,111 @@ +"""SCons.Tool.gcc + +Tool-specific initialization for gcc. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/gcc.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +from . import cc +import os +import re +import subprocess + +import SCons.Util + +compilers = ['gcc', 'cc'] + + +def generate(env): + """Add Builders and construction variables for gcc to an Environment.""" + + if 'CC' not in env: + env['CC'] = env.Detect(compilers) or compilers[0] + + cc.generate(env) + + if env['PLATFORM'] in ['cygwin', 'win32']: + env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS') + else: + env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS -fPIC') + # determine compiler version + version = detect_version(env, env['CC']) + if version: + env['CCVERSION'] = version + + +def exists(env): + # is executable, and is a GNU compiler (or accepts '--version' at least) + return detect_version(env, env.Detect(env.get('CC', compilers))) + + +def detect_version(env, cc): + """Return the version of the GNU compiler, or None if it is not a GNU compiler.""" + version = None + cc = env.subst(cc) + if not cc: + return version + + # -dumpversion was added in GCC 3.0. As long as we're supporting + # GCC versions older than that, we should use --version and a + # regular expression. + # pipe = SCons.Action._subproc(env, SCons.Util.CLVar(cc) + ['-dumpversion'], + pipe = SCons.Action._subproc(env, SCons.Util.CLVar(cc) + ['--version'], + stdin='devnull', + stderr='devnull', + stdout=subprocess.PIPE) + if pipe.wait() != 0: + return version + + with pipe.stdout: + # -dumpversion variant: + # line = pipe.stdout.read().strip() + # --version variant: + line = SCons.Util.to_str(pipe.stdout.readline()) + # Non-GNU compiler's output (like AIX xlc's) may exceed the stdout buffer: + # So continue with reading to let the child process actually terminate. + while SCons.Util.to_str(pipe.stdout.readline()): + pass + + # -dumpversion variant: + # if line: + # version = line + # --version variant: + match = re.search(r'[0-9]+(\.[0-9]+)+', line) + if match: + version = match.group(0) + + return version + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/gdc.py b/tools/scons/scons-local-3.0.5/SCons/Tool/gdc.py new file mode 100755 index 0000000000..2e5f03bfcf --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/gdc.py @@ -0,0 +1,145 @@ +from __future__ import print_function + +"""SCons.Tool.gdc + +Tool-specific initialization for the GDC compiler. +(https://github.com/D-Programming-GDC/GDC) + +Developed by Russel Winder (russel@winder.org.uk) +2012-05-09 onwards + +Compiler variables: + DC - The name of the D compiler to use. Defaults to gdc. + DPATH - List of paths to search for import modules. + DVERSIONS - List of version tags to enable when compiling. + DDEBUG - List of debug tags to enable when compiling. + +Linker related variables: + LIBS - List of library files to link in. + DLINK - Name of the linker to use. Defaults to gdc. + DLINKFLAGS - List of linker flags. + +Lib tool variables: + DLIB - Name of the lib tool to use. Defaults to lib. + DLIBFLAGS - List of flags to pass to the lib tool. + LIBS - Same as for the linker. (libraries to pull into the .lib) +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/gdc.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Action +import SCons.Defaults +import SCons.Tool + +import SCons.Tool.DCommon as DCommon + + +def generate(env): + static_obj, shared_obj = SCons.Tool.createObjBuilders(env) + + static_obj.add_action('.d', SCons.Defaults.DAction) + shared_obj.add_action('.d', SCons.Defaults.ShDAction) + static_obj.add_emitter('.d', SCons.Defaults.StaticObjectEmitter) + shared_obj.add_emitter('.d', SCons.Defaults.SharedObjectEmitter) + + env['DC'] = env.Detect('gdc') or 'gdc' + env['DCOM'] = '$DC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -c -o $TARGET $SOURCES' + env['_DINCFLAGS'] = '${_concat(DINCPREFIX, DPATH, DINCSUFFIX, __env__, RDirs, TARGET, SOURCE)}' + env['_DVERFLAGS'] = '${_concat(DVERPREFIX, DVERSIONS, DVERSUFFIX, __env__)}' + env['_DDEBUGFLAGS'] = '${_concat(DDEBUGPREFIX, DDEBUG, DDEBUGSUFFIX, __env__)}' + env['_DFLAGS'] = '${_concat(DFLAGPREFIX, DFLAGS, DFLAGSUFFIX, __env__)}' + + env['SHDC'] = '$DC' + env['SHDCOM'] = '$SHDC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -fPIC -c -o $TARGET $SOURCES' + + env['DPATH'] = ['#/'] + env['DFLAGS'] = [] + env['DVERSIONS'] = [] + env['DDEBUG'] = [] + + if env['DC']: + DCommon.addDPATHToEnv(env, env['DC']) + + env['DINCPREFIX'] = '-I' + env['DINCSUFFIX'] = '' + env['DVERPREFIX'] = '-version=' + env['DVERSUFFIX'] = '' + env['DDEBUGPREFIX'] = '-debug=' + env['DDEBUGSUFFIX'] = '' + env['DFLAGPREFIX'] = '-' + env['DFLAGSUFFIX'] = '' + env['DFILESUFFIX'] = '.d' + + env['DLINK'] = '$DC' + env['DLINKFLAGS'] = SCons.Util.CLVar('') + env['DLINKCOM'] = '$DLINK -o $TARGET $DLINKFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS' + + env['SHDLINK'] = '$DC' + env['SHDLINKFLAGS'] = SCons.Util.CLVar('$DLINKFLAGS -shared -shared-libphobos') + env['SHDLINKCOM'] = '$DLINK -o $TARGET $SHDLINKFLAGS $__SHDLIBVERSIONFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS' + + env['DLIB'] = 'lib' if env['PLATFORM'] == 'win32' else 'ar cr' + env['DLIBCOM'] = '$DLIB $_DLIBFLAGS {0}$TARGET $SOURCES $_DLINKLIBFLAGS'.format('-c ' if env['PLATFORM'] == 'win32' else '') + + env['_DLIBFLAGS'] = '${_concat(DLIBFLAGPREFIX, DLIBFLAGS, DLIBFLAGSUFFIX, __env__)}' + + env['DLIBFLAGPREFIX'] = '-' + env['DLIBFLAGSUFFIX'] = '' + env['DLINKFLAGPREFIX'] = '-' + env['DLINKFLAGSUFFIX'] = '' + + # __RPATH is set to $_RPATH in the platform specification if that + # platform supports it. + env['RPATHPREFIX'] = '-Wl,-rpath=' + env['RPATHSUFFIX'] = '' + env['_RPATH'] = '${_concat(RPATHPREFIX, RPATH, RPATHSUFFIX, __env__)}' + + # Support for versioned libraries + env['_SHDLIBVERSIONFLAGS'] = '$SHDLIBVERSIONFLAGS -Wl,-soname=$_SHDLIBSONAME' + env['_SHDLIBSONAME'] = '${DShLibSonameGenerator(__env__,TARGET)}' + # NOTE: this is a quick hack, the soname will only work if there is + # c/c++ linker loaded which provides callback for the ShLibSonameGenerator + env['DShLibSonameGenerator'] = SCons.Tool.ShLibSonameGenerator + # NOTE: this is only for further reference, currently $SHDLIBVERSION does + # not work, the user must use $SHLIBVERSION + env['SHDLIBVERSION'] = '$SHLIBVERSION' + env['SHDLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS' + + env['BUILDERS']['ProgramAllAtOnce'] = SCons.Builder.Builder( + action='$DC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -o $TARGET $DLINKFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS', + emitter=DCommon.allAtOnceEmitter, + ) + + +def exists(env): + return env.Detect('gdc') + + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/gettext_tool.py b/tools/scons/scons-local-3.0.5/SCons/Tool/gettext_tool.py new file mode 100755 index 0000000000..504ec46442 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/gettext_tool.py @@ -0,0 +1,60 @@ +"""gettext tool +""" + + +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +__revision__ = "src/engine/SCons/Tool/gettext_tool.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +############################################################################# +def generate(env,**kw): + import sys + import os + import SCons.Tool + from SCons.Platform.mingw import MINGW_DEFAULT_PATHS + from SCons.Platform.cygwin import CYGWIN_DEFAULT_PATHS + + from SCons.Tool.GettextCommon \ + import _translate, tool_list + for t in tool_list(env['PLATFORM'], env): + if sys.platform == 'win32': + tool = SCons.Tool.find_program_path(env, t, default_paths=MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS ) + if tool: + tool_bin_dir = os.path.dirname(tool) + env.AppendENVPath('PATH', tool_bin_dir) + else: + SCons.Warnings.Warning(t + ' tool requested, but binary not found in ENV PATH') + env.Tool(t) + env.AddMethod(_translate, 'Translate') +############################################################################# + +############################################################################# +def exists(env): + from SCons.Tool.GettextCommon \ + import _xgettext_exists, _msginit_exists, \ + _msgmerge_exists, _msgfmt_exists + try: + return _xgettext_exists(env) and _msginit_exists(env) \ + and _msgmerge_exists(env) and _msgfmt_exists(env) + except: + return False +############################################################################# diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/gfortran.py b/tools/scons/scons-local-3.0.5/SCons/Tool/gfortran.py new file mode 100755 index 0000000000..e543efd208 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/gfortran.py @@ -0,0 +1,66 @@ +"""SCons.Tool.gfortran + +Tool-specific initialization for gfortran, the GNU Fortran 95/Fortran +2003 compiler. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/gfortran.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Util + +from . import fortran + +def generate(env): + """Add Builders and construction variables for gfortran to an + Environment.""" + fortran.generate(env) + + for dialect in ['F77', 'F90', 'FORTRAN', 'F95', 'F03', 'F08']: + env['%s' % dialect] = 'gfortran' + env['SH%s' % dialect] = '$%s' % dialect + if env['PLATFORM'] in ['cygwin', 'win32']: + env['SH%sFLAGS' % dialect] = SCons.Util.CLVar('$%sFLAGS' % dialect) + else: + env['SH%sFLAGS' % dialect] = SCons.Util.CLVar('$%sFLAGS -fPIC' % dialect) + + env['INC%sPREFIX' % dialect] = "-I" + env['INC%sSUFFIX' % dialect] = "" + + env['FORTRANMODDIRPREFIX'] = "-J" + +def exists(env): + return env.Detect('gfortran') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/gnulink.py b/tools/scons/scons-local-3.0.5/SCons/Tool/gnulink.py new file mode 100755 index 0000000000..cf8a65d034 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/gnulink.py @@ -0,0 +1,80 @@ +"""SCons.Tool.gnulink + +Tool-specific initialization for the gnu linker. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/gnulink.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Util +import SCons.Tool +import os +import sys +import re + +from . import link + + +def generate(env): + """Add Builders and construction variables for gnulink to an Environment.""" + link.generate(env) + + if env['PLATFORM'] == 'hpux': + env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared -fPIC') + + # __RPATH is set to $_RPATH in the platform specification if that + # platform supports it. + env['RPATHPREFIX'] = '-Wl,-rpath=' + env['RPATHSUFFIX'] = '' + env['_RPATH'] = '${_concat(RPATHPREFIX, RPATH, RPATHSUFFIX, __env__)}' + + # OpenBSD doesn't usually use SONAME for libraries + use_soname = not sys.platform.startswith('openbsd') + link._setup_versioned_lib_variables(env, tool = 'gnulink', use_soname = use_soname) + env['LINKCALLBACKS'] = link._versioned_lib_callbacks() + + # For backward-compatibility with older SCons versions + env['SHLIBVERSIONFLAGS'] = SCons.Util.CLVar('-Wl,-Bsymbolic') + +def exists(env): + # TODO: sync with link.smart_link() to choose a linker + linkers = { 'CXX': ['g++'], 'CC': ['gcc'] } + alltools = [] + for langvar, linktools in linkers.items(): + if langvar in env: # use CC over CXX when user specified CC but not CXX + return SCons.Tool.FindTool(linktools, env) + alltools.extend(linktools) + return SCons.Tool.FindTool(alltools, env) # find CXX or CC + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/gs.py b/tools/scons/scons-local-3.0.5/SCons/Tool/gs.py new file mode 100755 index 0000000000..a1e0bd9862 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/gs.py @@ -0,0 +1,91 @@ +"""SCons.Tool.gs + +Tool-specific initialization for Ghostscript. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/gs.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Action +import SCons.Builder +import SCons.Platform +import SCons.Util + +# Ghostscript goes by different names on different platforms... +platform = SCons.Platform.platform_default() + +if platform == 'os2': + gs = 'gsos2' +elif platform == 'win32': + gs = 'gswin32c' +else: + gs = 'gs' + +GhostscriptAction = None + +def generate(env): + """Add Builders and construction variables for Ghostscript to an + Environment.""" + global GhostscriptAction + # The following try-except block enables us to use the Tool + # in standalone mode (without the accompanying pdf.py), + # whenever we need an explicit call of gs via the Gs() + # Builder ... + try: + if GhostscriptAction is None: + GhostscriptAction = SCons.Action.Action('$GSCOM', '$GSCOMSTR') + + from SCons.Tool import pdf + pdf.generate(env) + + bld = env['BUILDERS']['PDF'] + bld.add_action('.ps', GhostscriptAction) + except ImportError as e: + pass + + gsbuilder = SCons.Builder.Builder(action = SCons.Action.Action('$GSCOM', '$GSCOMSTR')) + env['BUILDERS']['Gs'] = gsbuilder + + env['GS'] = gs + env['GSFLAGS'] = SCons.Util.CLVar('-dNOPAUSE -dBATCH -sDEVICE=pdfwrite') + env['GSCOM'] = '$GS $GSFLAGS -sOutputFile=$TARGET $SOURCES' + + +def exists(env): + if 'PS2PDF' in env: + return env.Detect(env['PS2PDF']) + else: + return env.Detect(gs) or SCons.Util.WhereIs(gs) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/gxx.py b/tools/scons/scons-local-3.0.5/SCons/Tool/gxx.py new file mode 100755 index 0000000000..b98ae07d31 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/gxx.py @@ -0,0 +1,81 @@ +"""SCons.Tool.g++ + +Tool-specific initialization for g++. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/gxx.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os.path +import re +import subprocess + +import SCons.Tool +import SCons.Util + +from . import gcc +from . import cxx + +compilers = ['g++'] + + +def generate(env): + """Add Builders and construction variables for g++ to an Environment.""" + static_obj, shared_obj = SCons.Tool.createObjBuilders(env) + + if 'CXX' not in env: + env['CXX'] = env.Detect(compilers) or compilers[0] + + cxx.generate(env) + + # platform specific settings + if env['PLATFORM'] == 'aix': + env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS -mminimal-toc') + env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1 + env['SHOBJSUFFIX'] = '$OBJSUFFIX' + elif env['PLATFORM'] == 'hpux': + env['SHOBJSUFFIX'] = '.pic.o' + elif env['PLATFORM'] == 'sunos': + env['SHOBJSUFFIX'] = '.pic.o' + # determine compiler version + version = gcc.detect_version(env, env['CXX']) + if version: + env['CXXVERSION'] = version + + +def exists(env): + # is executable, and is a GNU compiler (or accepts '--version' at least) + return gcc.detect_version(env, env.Detect(env.get('CXX', compilers))) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/hpc++.py b/tools/scons/scons-local-3.0.5/SCons/Tool/hpc++.py new file mode 100755 index 0000000000..5cbe20e661 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/hpc++.py @@ -0,0 +1,45 @@ +"""SCons.Tool.hpc++ + +Tool-specific initialization for c++ on HP/UX. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/hpc++.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + + +#forward proxy to the preffered cxx version +from SCons.Tool.hpcxx import * + + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/hpcc.py b/tools/scons/scons-local-3.0.5/SCons/Tool/hpcc.py new file mode 100755 index 0000000000..27bdfa60c0 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/hpcc.py @@ -0,0 +1,53 @@ +"""SCons.Tool.hpcc + +Tool-specific initialization for HP aCC and cc. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/hpcc.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Util + +from . import cc + +def generate(env): + """Add Builders and construction variables for aCC & cc to an Environment.""" + cc.generate(env) + + env['CXX'] = 'aCC' + env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS +Z') + +def exists(env): + return env.Detect('aCC') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/hpcxx.py b/tools/scons/scons-local-3.0.5/SCons/Tool/hpcxx.py new file mode 100755 index 0000000000..6bfb600cc0 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/hpcxx.py @@ -0,0 +1,87 @@ +"""SCons.Tool.hpc++ + +Tool-specific initialization for c++ on HP/UX. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/hpcxx.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os.path + +import SCons.Util + +import SCons.Tool.cxx +cplusplus = SCons.Tool.cxx +#cplusplus = __import__('cxx', globals(), locals(), []) + + +acc = None + +# search for the acc compiler and linker front end + +try: + dirs = os.listdir('/opt') +except (IOError, OSError): + # Not being able to read the directory because it doesn't exist + # (IOError) or isn't readable (OSError) is okay. + dirs = [] + +for dir in dirs: + cc = '/opt/' + dir + '/bin/aCC' + if os.path.exists(cc): + acc = cc + break + + +def generate(env): + """Add Builders and construction variables for g++ to an Environment.""" + cplusplus.generate(env) + + if acc: + env['CXX'] = acc or 'aCC' + env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS +Z') + # determine version of aCC + line = os.popen(acc + ' -V 2>&1').readline().rstrip() + if line.find('aCC: HP ANSI C++') == 0: + env['CXXVERSION'] = line.split()[-1] + + if env['PLATFORM'] == 'cygwin': + env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS') + else: + env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS +Z') + +def exists(env): + return acc + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/hplink.py b/tools/scons/scons-local-3.0.5/SCons/Tool/hplink.py new file mode 100755 index 0000000000..502b9456e9 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/hplink.py @@ -0,0 +1,77 @@ +"""SCons.Tool.hplink + +Tool-specific initialization for the HP linker. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/hplink.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os +import os.path + +import SCons.Util + +from . import link + +ccLinker = None + +# search for the acc compiler and linker front end + +try: + dirs = os.listdir('/opt') +except (IOError, OSError): + # Not being able to read the directory because it doesn't exist + # (IOError) or isn't readable (OSError) is okay. + dirs = [] + +for dir in dirs: + linker = '/opt/' + dir + '/bin/aCC' + if os.path.exists(linker): + ccLinker = linker + break + +def generate(env): + """ + Add Builders and construction variables for Visual Age linker to + an Environment. + """ + link.generate(env) + + env['LINKFLAGS'] = SCons.Util.CLVar('-Wl,+s -Wl,+vnocompatwarnings') + env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -b') + env['SHLIBSUFFIX'] = '.sl' + +def exists(env): + return ccLinker + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/icc.py b/tools/scons/scons-local-3.0.5/SCons/Tool/icc.py new file mode 100755 index 0000000000..f16e79aafe --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/icc.py @@ -0,0 +1,59 @@ +"""engine.SCons.Tool.icc + +Tool-specific initialization for the OS/2 icc compiler. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/icc.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +from . import cc + +def generate(env): + """Add Builders and construction variables for the OS/2 to an Environment.""" + cc.generate(env) + + env['CC'] = 'icc' + env['CCCOM'] = '$CC $CFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET' + env['CXXCOM'] = '$CXX $CXXFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET' + env['CPPDEFPREFIX'] = '/D' + env['CPPDEFSUFFIX'] = '' + env['INCPREFIX'] = '/I' + env['INCSUFFIX'] = '' + env['CFILESUFFIX'] = '.c' + env['CXXFILESUFFIX'] = '.cc' + +def exists(env): + return env.Detect('icc') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/icl.py b/tools/scons/scons-local-3.0.5/SCons/Tool/icl.py new file mode 100755 index 0000000000..7a7b21b666 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/icl.py @@ -0,0 +1,52 @@ +"""engine.SCons.Tool.icl + +Tool-specific initialization for the Intel C/C++ compiler. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/icl.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Tool.intelc + +# This has been completely superseded by intelc.py, which can +# handle both Windows and Linux versions. + +def generate(*args, **kw): + """Add Builders and construction variables for icl to an Environment.""" + return SCons.Tool.intelc.generate(*args, **kw) + +def exists(*args, **kw): + return SCons.Tool.intelc.exists(*args, **kw) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/ifl.py b/tools/scons/scons-local-3.0.5/SCons/Tool/ifl.py new file mode 100755 index 0000000000..d351e4ed13 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/ifl.py @@ -0,0 +1,72 @@ +"""SCons.Tool.ifl + +Tool-specific initialization for the Intel Fortran compiler. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/ifl.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Defaults +from SCons.Scanner.Fortran import FortranScan +from .FortranCommon import add_all_to_env + +def generate(env): + """Add Builders and construction variables for ifl to an Environment.""" + fscan = FortranScan("FORTRANPATH") + SCons.Tool.SourceFileScanner.add_scanner('.i', fscan) + SCons.Tool.SourceFileScanner.add_scanner('.i90', fscan) + + if 'FORTRANFILESUFFIXES' not in env: + env['FORTRANFILESUFFIXES'] = ['.i'] + else: + env['FORTRANFILESUFFIXES'].append('.i') + + if 'F90FILESUFFIXES' not in env: + env['F90FILESUFFIXES'] = ['.i90'] + else: + env['F90FILESUFFIXES'].append('.i90') + + add_all_to_env(env) + + env['FORTRAN'] = 'ifl' + env['SHFORTRAN'] = '$FORTRAN' + env['FORTRANCOM'] = '$FORTRAN $FORTRANFLAGS $_FORTRANINCFLAGS /c $SOURCES /Fo$TARGET' + env['FORTRANPPCOM'] = '$FORTRAN $FORTRANFLAGS $CPPFLAGS $_CPPDEFFLAGS $_FORTRANINCFLAGS /c $SOURCES /Fo$TARGET' + env['SHFORTRANCOM'] = '$SHFORTRAN $SHFORTRANFLAGS $_FORTRANINCFLAGS /c $SOURCES /Fo$TARGET' + env['SHFORTRANPPCOM'] = '$SHFORTRAN $SHFORTRANFLAGS $CPPFLAGS $_CPPDEFFLAGS $_FORTRANINCFLAGS /c $SOURCES /Fo$TARGET' + +def exists(env): + return env.Detect('ifl') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/ifort.py b/tools/scons/scons-local-3.0.5/SCons/Tool/ifort.py new file mode 100755 index 0000000000..7a3128e14d --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/ifort.py @@ -0,0 +1,88 @@ +"""SCons.Tool.ifort + +Tool-specific initialization for newer versions of the Intel Fortran Compiler +for Linux/Windows (and possibly Mac OS X). + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/ifort.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Defaults +from SCons.Scanner.Fortran import FortranScan +from .FortranCommon import add_all_to_env + +def generate(env): + """Add Builders and construction variables for ifort to an Environment.""" + # ifort supports Fortran 90 and Fortran 95 + # Additionally, ifort recognizes more file extensions. + fscan = FortranScan("FORTRANPATH") + SCons.Tool.SourceFileScanner.add_scanner('.i', fscan) + SCons.Tool.SourceFileScanner.add_scanner('.i90', fscan) + + if 'FORTRANFILESUFFIXES' not in env: + env['FORTRANFILESUFFIXES'] = ['.i'] + else: + env['FORTRANFILESUFFIXES'].append('.i') + + if 'F90FILESUFFIXES' not in env: + env['F90FILESUFFIXES'] = ['.i90'] + else: + env['F90FILESUFFIXES'].append('.i90') + + add_all_to_env(env) + + fc = 'ifort' + + for dialect in ['F77', 'F90', 'FORTRAN', 'F95']: + env['%s' % dialect] = fc + env['SH%s' % dialect] = '$%s' % dialect + if env['PLATFORM'] == 'posix': + env['SH%sFLAGS' % dialect] = SCons.Util.CLVar('$%sFLAGS -fPIC' % dialect) + + if env['PLATFORM'] == 'win32': + # On Windows, the ifort compiler specifies the object on the + # command line with -object:, not -o. Massage the necessary + # command-line construction variables. + for dialect in ['F77', 'F90', 'FORTRAN', 'F95']: + for var in ['%sCOM' % dialect, '%sPPCOM' % dialect, + 'SH%sCOM' % dialect, 'SH%sPPCOM' % dialect]: + env[var] = env[var].replace('-o $TARGET', '-object:$TARGET') + env['FORTRANMODDIRPREFIX'] = "/module:" + else: + env['FORTRANMODDIRPREFIX'] = "-module " + +def exists(env): + return env.Detect('ifort') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/ilink.py b/tools/scons/scons-local-3.0.5/SCons/Tool/ilink.py new file mode 100755 index 0000000000..c27443a621 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/ilink.py @@ -0,0 +1,59 @@ +"""SCons.Tool.ilink + +Tool-specific initialization for the OS/2 ilink linker. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/ilink.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Defaults +import SCons.Tool +import SCons.Util + +def generate(env): + """Add Builders and construction variables for ilink to an Environment.""" + SCons.Tool.createProgBuilder(env) + + env['LINK'] = 'ilink' + env['LINKFLAGS'] = SCons.Util.CLVar('') + env['LINKCOM'] = '$LINK $LINKFLAGS /O:$TARGET $SOURCES $_LIBDIRFLAGS $_LIBFLAGS' + env['LIBDIRPREFIX']='/LIBPATH:' + env['LIBDIRSUFFIX']='' + env['LIBLINKPREFIX']='' + env['LIBLINKSUFFIX']='$LIBSUFFIX' + +def exists(env): + return env.Detect('ilink') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/ilink32.py b/tools/scons/scons-local-3.0.5/SCons/Tool/ilink32.py new file mode 100755 index 0000000000..69430ec1e5 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/ilink32.py @@ -0,0 +1,60 @@ +"""SCons.Tool.ilink32 + +XXX + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/ilink32.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Tool +import SCons.Tool.bcc32 +import SCons.Util + +def generate(env): + """Add Builders and construction variables for Borland ilink to an + Environment.""" + SCons.Tool.createSharedLibBuilder(env) + SCons.Tool.createProgBuilder(env) + + env['LINK'] = '$CC' + env['LINKFLAGS'] = SCons.Util.CLVar('') + env['LINKCOM'] = '$LINK -q $LINKFLAGS -e$TARGET $SOURCES $LIBS' + env['LIBDIRPREFIX']='' + env['LIBDIRSUFFIX']='' + env['LIBLINKPREFIX']='' + env['LIBLINKSUFFIX']='$LIBSUFFIX' + + +def exists(env): + # Uses bcc32 to do linking as it generally knows where the standard + # LIBS are and set up the linking correctly + return SCons.Tool.bcc32.findIt('bcc32', env) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/install.py b/tools/scons/scons-local-3.0.5/SCons/Tool/install.py new file mode 100755 index 0000000000..c388b2a211 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/install.py @@ -0,0 +1,428 @@ +"""SCons.Tool.install + +Tool-specific initialization for the install tool. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +from __future__ import print_function + +__revision__ = "src/engine/SCons/Tool/install.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os +import re +import shutil +import stat + +import SCons.Action +import SCons.Tool +import SCons.Util + +# +# We keep track of *all* installed files. +_INSTALLED_FILES = [] +_UNIQUE_INSTALLED_FILES = None + +class CopytreeError(EnvironmentError): + pass + +# This is a patched version of shutil.copytree from python 2.5. It +# doesn't fail if the dir exists, which regular copytree does +# (annoyingly). Note the XXX comment in the docstring. +def scons_copytree(src, dst, symlinks=False): + """Recursively copy a directory tree using copy2(). + + The destination directory must not already exist. + If exception(s) occur, an CopytreeError is raised with a list of reasons. + + If the optional symlinks flag is true, symbolic links in the + source tree result in symbolic links in the destination tree; if + it is false, the contents of the files pointed to by symbolic + links are copied. + + XXX Consider this example code rather than the ultimate tool. + + """ + names = os.listdir(src) + # garyo@genarts.com fix: check for dir before making dirs. + if not os.path.exists(dst): + os.makedirs(dst) + errors = [] + for name in names: + srcname = os.path.join(src, name) + dstname = os.path.join(dst, name) + try: + if symlinks and os.path.islink(srcname): + linkto = os.readlink(srcname) + os.symlink(linkto, dstname) + elif os.path.isdir(srcname): + scons_copytree(srcname, dstname, symlinks) + else: + shutil.copy2(srcname, dstname) + # XXX What about devices, sockets etc.? + except (IOError, os.error) as why: + errors.append((srcname, dstname, str(why))) + # catch the CopytreeError from the recursive copytree so that we can + # continue with other files + except CopytreeError as err: + errors.extend(err.args[0]) + try: + shutil.copystat(src, dst) + except SCons.Util.WinError: + # can't copy file access times on Windows + pass + except OSError as why: + errors.extend((src, dst, str(why))) + if errors: + raise CopytreeError(errors) + + +# +# Functions doing the actual work of the Install Builder. +# +def copyFunc(dest, source, env): + """Install a source file or directory into a destination by copying, + (including copying permission/mode bits).""" + + if os.path.isdir(source): + if os.path.exists(dest): + if not os.path.isdir(dest): + raise SCons.Errors.UserError("cannot overwrite non-directory `%s' with a directory `%s'" % (str(dest), str(source))) + else: + parent = os.path.split(dest)[0] + if not os.path.exists(parent): + os.makedirs(parent) + scons_copytree(source, dest) + else: + shutil.copy2(source, dest) + st = os.stat(source) + os.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE) + + return 0 + +# +# Functions doing the actual work of the InstallVersionedLib Builder. +# +def copyFuncVersionedLib(dest, source, env): + """Install a versioned library into a destination by copying, + (including copying permission/mode bits) and then creating + required symlinks.""" + + if os.path.isdir(source): + raise SCons.Errors.UserError("cannot install directory `%s' as a version library" % str(source) ) + else: + # remove the link if it is already there + try: + os.remove(dest) + except: + pass + shutil.copy2(source, dest) + st = os.stat(source) + os.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE) + installShlibLinks(dest, source, env) + + return 0 + +def listShlibLinksToInstall(dest, source, env): + install_links = [] + source = env.arg2nodes(source) + dest = env.fs.File(dest) + install_dir = dest.get_dir() + for src in source: + symlinks = getattr(getattr(src,'attributes',None), 'shliblinks', None) + if symlinks: + for link, linktgt in symlinks: + link_base = os.path.basename(link.get_path()) + linktgt_base = os.path.basename(linktgt.get_path()) + install_link = env.fs.File(link_base, install_dir) + install_linktgt = env.fs.File(linktgt_base, install_dir) + install_links.append((install_link, install_linktgt)) + return install_links + +def installShlibLinks(dest, source, env): + """If we are installing a versioned shared library create the required links.""" + Verbose = False + symlinks = listShlibLinksToInstall(dest, source, env) + if Verbose: + print('installShlibLinks: symlinks={:r}'.format(SCons.Tool.StringizeLibSymlinks(symlinks))) + if symlinks: + SCons.Tool.CreateLibSymlinks(env, symlinks) + return + +def installFunc(target, source, env): + """Install a source file into a target using the function specified + as the INSTALL construction variable.""" + try: + install = env['INSTALL'] + except KeyError: + raise SCons.Errors.UserError('Missing INSTALL construction variable.') + + assert len(target)==len(source), \ + "Installing source %s into target %s: target and source lists must have same length."%(list(map(str, source)), list(map(str, target))) + for t,s in zip(target,source): + if install(t.get_path(),s.get_path(),env): + return 1 + + return 0 + +def installFuncVersionedLib(target, source, env): + """Install a versioned library into a target using the function specified + as the INSTALLVERSIONEDLIB construction variable.""" + try: + install = env['INSTALLVERSIONEDLIB'] + except KeyError: + raise SCons.Errors.UserError('Missing INSTALLVERSIONEDLIB construction variable.') + + assert len(target)==len(source), \ + "Installing source %s into target %s: target and source lists must have same length."%(list(map(str, source)), list(map(str, target))) + for t,s in zip(target,source): + if hasattr(t.attributes, 'shlibname'): + tpath = os.path.join(t.get_dir(), t.attributes.shlibname) + else: + tpath = t.get_path() + if install(tpath,s.get_path(),env): + return 1 + + return 0 + +def stringFunc(target, source, env): + installstr = env.get('INSTALLSTR') + if installstr: + return env.subst_target_source(installstr, 0, target, source) + target = str(target[0]) + source = str(source[0]) + if os.path.isdir(source): + type = 'directory' + else: + type = 'file' + return 'Install %s: "%s" as "%s"' % (type, source, target) + +# +# Emitter functions +# +def add_targets_to_INSTALLED_FILES(target, source, env): + """ An emitter that adds all target files to the list stored in the + _INSTALLED_FILES global variable. This way all installed files of one + scons call will be collected. + """ + global _INSTALLED_FILES, _UNIQUE_INSTALLED_FILES + _INSTALLED_FILES.extend(target) + + _UNIQUE_INSTALLED_FILES = None + return (target, source) + +def add_versioned_targets_to_INSTALLED_FILES(target, source, env): + """ An emitter that adds all target files to the list stored in the + _INSTALLED_FILES global variable. This way all installed files of one + scons call will be collected. + """ + global _INSTALLED_FILES, _UNIQUE_INSTALLED_FILES + Verbose = False + _INSTALLED_FILES.extend(target) + if Verbose: + print("add_versioned_targets_to_INSTALLED_FILES: target={:r}".format(list(map(str, target)))) + symlinks = listShlibLinksToInstall(target[0], source, env) + if symlinks: + SCons.Tool.EmitLibSymlinks(env, symlinks, target[0]) + _UNIQUE_INSTALLED_FILES = None + return (target, source) + +class DESTDIR_factory(object): + """ A node factory, where all files will be relative to the dir supplied + in the constructor. + """ + def __init__(self, env, dir): + self.env = env + self.dir = env.arg2nodes( dir, env.fs.Dir )[0] + + def Entry(self, name): + name = SCons.Util.make_path_relative(name) + return self.dir.Entry(name) + + def Dir(self, name): + name = SCons.Util.make_path_relative(name) + return self.dir.Dir(name) + +# +# The Builder Definition +# +install_action = SCons.Action.Action(installFunc, stringFunc) +installas_action = SCons.Action.Action(installFunc, stringFunc) +installVerLib_action = SCons.Action.Action(installFuncVersionedLib, stringFunc) + +BaseInstallBuilder = None + +def InstallBuilderWrapper(env, target=None, source=None, dir=None, **kw): + if target and dir: + import SCons.Errors + raise SCons.Errors.UserError("Both target and dir defined for Install(), only one may be defined.") + if not dir: + dir=target + + import SCons.Script + install_sandbox = SCons.Script.GetOption('install_sandbox') + if install_sandbox: + target_factory = DESTDIR_factory(env, install_sandbox) + else: + target_factory = env.fs + + try: + dnodes = env.arg2nodes(dir, target_factory.Dir) + except TypeError: + raise SCons.Errors.UserError("Target `%s' of Install() is a file, but should be a directory. Perhaps you have the Install() arguments backwards?" % str(dir)) + sources = env.arg2nodes(source, env.fs.Entry) + tgt = [] + for dnode in dnodes: + for src in sources: + # Prepend './' so the lookup doesn't interpret an initial + # '#' on the file name portion as meaning the Node should + # be relative to the top-level SConstruct directory. + target = env.fs.Entry('.'+os.sep+src.name, dnode) + tgt.extend(BaseInstallBuilder(env, target, src, **kw)) + return tgt + + +def InstallAsBuilderWrapper(env, target=None, source=None, **kw): + result = [] + for src, tgt in map(lambda x, y: (x, y), source, target): + result.extend(BaseInstallBuilder(env, tgt, src, **kw)) + return result + +BaseVersionedInstallBuilder = None + + +def InstallVersionedBuilderWrapper(env, target=None, source=None, dir=None, **kw): + if target and dir: + import SCons.Errors + raise SCons.Errors.UserError("Both target and dir defined for Install(), only one may be defined.") + if not dir: + dir=target + + import SCons.Script + install_sandbox = SCons.Script.GetOption('install_sandbox') + if install_sandbox: + target_factory = DESTDIR_factory(env, install_sandbox) + else: + target_factory = env.fs + + try: + dnodes = env.arg2nodes(dir, target_factory.Dir) + except TypeError: + raise SCons.Errors.UserError("Target `%s' of Install() is a file, but should be a directory. Perhaps you have the Install() arguments backwards?" % str(dir)) + sources = env.arg2nodes(source, env.fs.Entry) + tgt = [] + for dnode in dnodes: + for src in sources: + # Prepend './' so the lookup doesn't interpret an initial + # '#' on the file name portion as meaning the Node should + # be relative to the top-level SConstruct directory. + target = env.fs.Entry('.'+os.sep+src.name, dnode) + tgt.extend(BaseVersionedInstallBuilder(env, target, src, **kw)) + return tgt + +added = None + + +def generate(env): + + from SCons.Script import AddOption, GetOption + global added + if not added: + added = 1 + AddOption('--install-sandbox', + dest='install_sandbox', + type="string", + action="store", + help='A directory under which all installed files will be placed.') + + global BaseInstallBuilder + if BaseInstallBuilder is None: + install_sandbox = GetOption('install_sandbox') + if install_sandbox: + target_factory = DESTDIR_factory(env, install_sandbox) + else: + target_factory = env.fs + + BaseInstallBuilder = SCons.Builder.Builder( + action = install_action, + target_factory = target_factory.Entry, + source_factory = env.fs.Entry, + multi = 1, + emitter = [ add_targets_to_INSTALLED_FILES, ], + source_scanner = SCons.Scanner.Base( {}, name = 'Install', recursive = False ), + name = 'InstallBuilder') + + global BaseVersionedInstallBuilder + if BaseVersionedInstallBuilder is None: + install_sandbox = GetOption('install_sandbox') + if install_sandbox: + target_factory = DESTDIR_factory(env, install_sandbox) + else: + target_factory = env.fs + + BaseVersionedInstallBuilder = SCons.Builder.Builder( + action = installVerLib_action, + target_factory = target_factory.Entry, + source_factory = env.fs.Entry, + multi = 1, + emitter = [ add_versioned_targets_to_INSTALLED_FILES, ], + name = 'InstallVersionedBuilder') + + env['BUILDERS']['_InternalInstall'] = InstallBuilderWrapper + env['BUILDERS']['_InternalInstallAs'] = InstallAsBuilderWrapper + env['BUILDERS']['_InternalInstallVersionedLib'] = InstallVersionedBuilderWrapper + + # We'd like to initialize this doing something like the following, + # but there isn't yet support for a ${SOURCE.type} expansion that + # will print "file" or "directory" depending on what's being + # installed. For now we punt by not initializing it, and letting + # the stringFunc() that we put in the action fall back to the + # hand-crafted default string if it's not set. + # + #try: + # env['INSTALLSTR'] + #except KeyError: + # env['INSTALLSTR'] = 'Install ${SOURCE.type}: "$SOURCES" as "$TARGETS"' + + try: + env['INSTALL'] + except KeyError: + env['INSTALL'] = copyFunc + + try: + env['INSTALLVERSIONEDLIB'] + except KeyError: + env['INSTALLVERSIONEDLIB'] = copyFuncVersionedLib + +def exists(env): + return 1 + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/intelc.py b/tools/scons/scons-local-3.0.5/SCons/Tool/intelc.py new file mode 100755 index 0000000000..63df4117c7 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/intelc.py @@ -0,0 +1,613 @@ +"""SCons.Tool.icl + +Tool-specific initialization for the Intel C/C++ compiler. +Supports Linux and Windows compilers, v7 and up. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from __future__ import division, print_function + +__revision__ = "src/engine/SCons/Tool/intelc.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import math, sys, os.path, glob, string, re + +is_windows = sys.platform == 'win32' +is_win64 = is_windows and (os.environ['PROCESSOR_ARCHITECTURE'] == 'AMD64' or + ('PROCESSOR_ARCHITEW6432' in os.environ and + os.environ['PROCESSOR_ARCHITEW6432'] == 'AMD64')) +is_linux = sys.platform.startswith('linux') +is_mac = sys.platform == 'darwin' + +if is_windows: + import SCons.Tool.msvc +elif is_linux: + import SCons.Tool.gcc +elif is_mac: + import SCons.Tool.gcc +import SCons.Util +import SCons.Warnings + +# Exceptions for this tool +class IntelCError(SCons.Errors.InternalError): + pass +class MissingRegistryError(IntelCError): # missing registry entry + pass +class MissingDirError(IntelCError): # dir not found + pass +class NoRegistryModuleError(IntelCError): # can't read registry at all + pass + +def linux_ver_normalize(vstr): + """Normalize a Linux compiler version number. + Intel changed from "80" to "9.0" in 2005, so we assume if the number + is greater than 60 it's an old-style number and otherwise new-style. + Always returns an old-style float like 80 or 90 for compatibility with Windows. + Shades of Y2K!""" + # Check for version number like 9.1.026: return 91.026 + # XXX needs to be updated for 2011+ versions (like 2011.11.344 which is compiler v12.1.5) + m = re.match(r'([0-9]+)\.([0-9]+)\.([0-9]+)', vstr) + if m: + vmaj,vmin,build = m.groups() + return float(vmaj) * 10. + float(vmin) + float(build) / 1000. + else: + f = float(vstr) + if is_windows: + return f + else: + if f < 60: return f * 10.0 + else: return f + +def check_abi(abi): + """Check for valid ABI (application binary interface) name, + and map into canonical one""" + if not abi: + return None + abi = abi.lower() + # valid_abis maps input name to canonical name + if is_windows: + valid_abis = {'ia32' : 'ia32', + 'x86' : 'ia32', + 'ia64' : 'ia64', + 'em64t' : 'em64t', + 'amd64' : 'em64t'} + if is_linux: + valid_abis = {'ia32' : 'ia32', + 'x86' : 'ia32', + 'x86_64' : 'x86_64', + 'em64t' : 'x86_64', + 'amd64' : 'x86_64'} + if is_mac: + valid_abis = {'ia32' : 'ia32', + 'x86' : 'ia32', + 'x86_64' : 'x86_64', + 'em64t' : 'x86_64'} + try: + abi = valid_abis[abi] + except KeyError: + raise SCons.Errors.UserError("Intel compiler: Invalid ABI %s, valid values are %s"% \ + (abi, list(valid_abis.keys()))) + return abi + +def vercmp(a, b): + """Compare strings as floats, + but Intel changed Linux naming convention at 9.0""" + return cmp(linux_ver_normalize(b), linux_ver_normalize(a)) + +def get_version_from_list(v, vlist): + """See if we can match v (string) in vlist (list of strings) + Linux has to match in a fuzzy way.""" + if is_windows: + # Simple case, just find it in the list + if v in vlist: return v + else: return None + else: + # Fuzzy match: normalize version number first, but still return + # original non-normalized form. + fuzz = 0.001 + for vi in vlist: + if math.fabs(linux_ver_normalize(vi) - linux_ver_normalize(v)) < fuzz: + return vi + # Not found + return None + +def get_intel_registry_value(valuename, version=None, abi=None): + """ + Return a value from the Intel compiler registry tree. (Windows only) + """ + # Open the key: + if is_win64: + K = 'Software\\Wow6432Node\\Intel\\Compilers\\C++\\' + version + '\\'+abi.upper() + else: + K = 'Software\\Intel\\Compilers\\C++\\' + version + '\\'+abi.upper() + try: + k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, K) + except SCons.Util.RegError: + # For version 13 and later, check UUID subkeys for valuename + if is_win64: + K = 'Software\\Wow6432Node\\Intel\\Suites\\' + version + "\\Defaults\\C++\\" + abi.upper() + else: + K = 'Software\\Intel\\Suites\\' + version + "\\Defaults\\C++\\" + abi.upper() + try: + k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, K) + uuid = SCons.Util.RegQueryValueEx(k, 'SubKey')[0] + + if is_win64: + K = 'Software\\Wow6432Node\\Intel\\Suites\\' + version + "\\" + uuid + "\\C++" + else: + K = 'Software\\Intel\\Suites\\' + version + "\\" + uuid + "\\C++" + k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, K) + + try: + v = SCons.Util.RegQueryValueEx(k, valuename)[0] + return v # or v.encode('iso-8859-1', 'replace') to remove unicode? + except SCons.Util.RegError: + if abi.upper() == 'EM64T': + abi = 'em64t_native' + if is_win64: + K = 'Software\\Wow6432Node\\Intel\\Suites\\' + version + "\\" + uuid + "\\C++\\" + abi.upper() + else: + K = 'Software\\Intel\\Suites\\' + version + "\\" + uuid + "\\C++\\" + abi.upper() + k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, K) + + try: + v = SCons.Util.RegQueryValueEx(k, valuename)[0] + return v # or v.encode('iso-8859-1', 'replace') to remove unicode? + except SCons.Util.RegError: + raise MissingRegistryError("%s was not found in the registry, for Intel compiler version %s, abi='%s'"%(K, version,abi)) + + except SCons.Util.RegError: + raise MissingRegistryError("%s was not found in the registry, for Intel compiler version %s, abi='%s'"%(K, version,abi)) + except SCons.Util.WinError: + raise MissingRegistryError("%s was not found in the registry, for Intel compiler version %s, abi='%s'"%(K, version,abi)) + + # Get the value: + try: + v = SCons.Util.RegQueryValueEx(k, valuename)[0] + return v # or v.encode('iso-8859-1', 'replace') to remove unicode? + except SCons.Util.RegError: + raise MissingRegistryError("%s\\%s was not found in the registry."%(K, valuename)) + + +def get_all_compiler_versions(): + """Returns a sorted list of strings, like "70" or "80" or "9.0" + with most recent compiler version first. + """ + versions=[] + if is_windows: + if is_win64: + keyname = 'Software\\WoW6432Node\\Intel\\Compilers\\C++' + else: + keyname = 'Software\\Intel\\Compilers\\C++' + try: + k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, + keyname) + except SCons.Util.WinError: + # For version 13 or later, check for default instance UUID + if is_win64: + keyname = 'Software\\WoW6432Node\\Intel\\Suites' + else: + keyname = 'Software\\Intel\\Suites' + try: + k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, + keyname) + except SCons.Util.WinError: + return [] + i = 0 + versions = [] + try: + while i < 100: + subkey = SCons.Util.RegEnumKey(k, i) # raises EnvironmentError + # Check that this refers to an existing dir. + # This is not 100% perfect but should catch common + # installation issues like when the compiler was installed + # and then the install directory deleted or moved (rather + # than uninstalling properly), so the registry values + # are still there. + if subkey == 'Defaults': # Ignore default instances + i = i + 1 + continue + ok = False + for try_abi in ('IA32', 'IA32e', 'IA64', 'EM64T'): + try: + d = get_intel_registry_value('ProductDir', subkey, try_abi) + except MissingRegistryError: + continue # not found in reg, keep going + if os.path.exists(d): ok = True + if ok: + versions.append(subkey) + else: + try: + # Registry points to nonexistent dir. Ignore this + # version. + value = get_intel_registry_value('ProductDir', subkey, 'IA32') + except MissingRegistryError as e: + + # Registry key is left dangling (potentially + # after uninstalling). + + print("scons: *** Ignoring the registry key for the Intel compiler version %s.\n" \ + "scons: *** It seems that the compiler was uninstalled and that the registry\n" \ + "scons: *** was not cleaned up properly.\n" % subkey) + else: + print("scons: *** Ignoring "+str(value)) + + i = i + 1 + except EnvironmentError: + # no more subkeys + pass + elif is_linux or is_mac: + for d in glob.glob('/opt/intel_cc_*'): + # Typical dir here is /opt/intel_cc_80. + m = re.search(r'cc_(.*)$', d) + if m: + versions.append(m.group(1)) + for d in glob.glob('/opt/intel/cc*/*'): + # Typical dir here is /opt/intel/cc/9.0 for IA32, + # /opt/intel/cce/9.0 for EMT64 (AMD64) + m = re.search(r'([0-9][0-9.]*)$', d) + if m: + versions.append(m.group(1)) + for d in glob.glob('/opt/intel/Compiler/*'): + # Typical dir here is /opt/intel/Compiler/11.1 + m = re.search(r'([0-9][0-9.]*)$', d) + if m: + versions.append(m.group(1)) + for d in glob.glob('/opt/intel/composerxe-*'): + # Typical dir here is /opt/intel/composerxe-2011.4.184 + m = re.search(r'([0-9][0-9.]*)$', d) + if m: + versions.append(m.group(1)) + for d in glob.glob('/opt/intel/composer_xe_*'): + # Typical dir here is /opt/intel/composer_xe_2011_sp1.11.344 + # The _sp1 is useless, the installers are named 2011.9.x, 2011.10.x, 2011.11.x + m = re.search(r'([0-9]{0,4})(?:_sp\d*)?\.([0-9][0-9.]*)$', d) + if m: + versions.append("%s.%s"%(m.group(1), m.group(2))) + for d in glob.glob('/opt/intel/compilers_and_libraries_*'): + # JPA: For the new version of Intel compiler 2016.1. + m = re.search(r'([0-9]{0,4})(?:_sp\d*)?\.([0-9][0-9.]*)$', d) + if m: + versions.append("%s.%s"%(m.group(1), m.group(2))) + + def keyfunc(str): + """Given a dot-separated version string, return a tuple of ints representing it.""" + return [int(x) for x in str.split('.')] + # split into ints, sort, then remove dups + return sorted(SCons.Util.unique(versions), key=keyfunc, reverse=True) + +def get_intel_compiler_top(version, abi): + """ + Return the main path to the top-level dir of the Intel compiler, + using the given version. + The compiler will be in /bin/icl.exe (icc on linux), + the include dir is /include, etc. + """ + + if is_windows: + if not SCons.Util.can_read_reg: + raise NoRegistryModuleError("No Windows registry module was found") + top = get_intel_registry_value('ProductDir', version, abi) + archdir={'x86_64': 'intel64', + 'amd64' : 'intel64', + 'em64t' : 'intel64', + 'x86' : 'ia32', + 'i386' : 'ia32', + 'ia32' : 'ia32' + }[abi] # for v11 and greater + # pre-11, icl was in Bin. 11 and later, it's in Bin/ apparently. + if not os.path.exists(os.path.join(top, "Bin", "icl.exe")) \ + and not os.path.exists(os.path.join(top, "Bin", abi, "icl.exe")) \ + and not os.path.exists(os.path.join(top, "Bin", archdir, "icl.exe")): + raise MissingDirError("Can't find Intel compiler in %s"%(top)) + elif is_mac or is_linux: + def find_in_2008style_dir(version): + # first dir is new (>=9.0) style, second is old (8.0) style. + dirs=('/opt/intel/cc/%s', '/opt/intel_cc_%s') + if abi == 'x86_64': + dirs=('/opt/intel/cce/%s',) # 'e' stands for 'em64t', aka x86_64 aka amd64 + top=None + for d in dirs: + if os.path.exists(os.path.join(d%version, "bin", "icc")): + top = d%version + break + return top + def find_in_2010style_dir(version): + dirs=('/opt/intel/Compiler/%s/*'%version) + # typically /opt/intel/Compiler/11.1/064 (then bin/intel64/icc) + dirs=glob.glob(dirs) + # find highest sub-version number by reverse sorting and picking first existing one. + dirs.sort() + dirs.reverse() + top=None + for d in dirs: + if (os.path.exists(os.path.join(d, "bin", "ia32", "icc")) or + os.path.exists(os.path.join(d, "bin", "intel64", "icc"))): + top = d + break + return top + def find_in_2011style_dir(version): + # The 2011 (compiler v12) dirs are inconsistent, so just redo the search from + # get_all_compiler_versions and look for a match (search the newest form first) + top=None + for d in glob.glob('/opt/intel/composer_xe_*'): + # Typical dir here is /opt/intel/composer_xe_2011_sp1.11.344 + # The _sp1 is useless, the installers are named 2011.9.x, 2011.10.x, 2011.11.x + m = re.search(r'([0-9]{0,4})(?:_sp\d*)?\.([0-9][0-9.]*)$', d) + if m: + cur_ver = "%s.%s"%(m.group(1), m.group(2)) + if cur_ver == version and \ + (os.path.exists(os.path.join(d, "bin", "ia32", "icc")) or + os.path.exists(os.path.join(d, "bin", "intel64", "icc"))): + top = d + break + if not top: + for d in glob.glob('/opt/intel/composerxe-*'): + # Typical dir here is /opt/intel/composerxe-2011.4.184 + m = re.search(r'([0-9][0-9.]*)$', d) + if m and m.group(1) == version and \ + (os.path.exists(os.path.join(d, "bin", "ia32", "icc")) or + os.path.exists(os.path.join(d, "bin", "intel64", "icc"))): + top = d + break + return top + def find_in_2016style_dir(version): + # The 2016 (compiler v16) dirs are inconsistent from previous. + top = None + for d in glob.glob('/opt/intel/compilers_and_libraries_%s/linux'%version): + if os.path.exists(os.path.join(d, "bin", "ia32", "icc")) or os.path.exists(os.path.join(d, "bin", "intel64", "icc")): + top = d + break + return top + + top = find_in_2016style_dir(version) or find_in_2011style_dir(version) or find_in_2010style_dir(version) or find_in_2008style_dir(version) + # print "INTELC: top=",top + if not top: + raise MissingDirError("Can't find version %s Intel compiler in %s (abi='%s')"%(version,top, abi)) + return top + + +def generate(env, version=None, abi=None, topdir=None, verbose=0): + """Add Builders and construction variables for Intel C/C++ compiler + to an Environment. + args: + version: (string) compiler version to use, like "80" + abi: (string) 'win32' or whatever Itanium version wants + topdir: (string) compiler top dir, like + "c:\Program Files\Intel\Compiler70" + If topdir is used, version and abi are ignored. + verbose: (int) if >0, prints compiler version used. + """ + if not (is_mac or is_linux or is_windows): + # can't handle this platform + return + + if is_windows: + SCons.Tool.msvc.generate(env) + elif is_linux: + SCons.Tool.gcc.generate(env) + elif is_mac: + SCons.Tool.gcc.generate(env) + + # if version is unspecified, use latest + vlist = get_all_compiler_versions() + if not version: + if vlist: + version = vlist[0] + else: + # User may have specified '90' but we need to get actual dirname '9.0'. + # get_version_from_list does that mapping. + v = get_version_from_list(version, vlist) + if not v: + raise SCons.Errors.UserError("Invalid Intel compiler version %s: "%version + \ + "installed versions are %s"%(', '.join(vlist))) + version = v + + # if abi is unspecified, use ia32 + # alternatives are ia64 for Itanium, or amd64 or em64t or x86_64 (all synonyms here) + abi = check_abi(abi) + if abi is None: + if is_mac or is_linux: + # Check if we are on 64-bit linux, default to 64 then. + uname_m = os.uname()[4] + if uname_m == 'x86_64': + abi = 'x86_64' + else: + abi = 'ia32' + else: + if is_win64: + abi = 'em64t' + else: + abi = 'ia32' + + if version and not topdir: + try: + topdir = get_intel_compiler_top(version, abi) + except (SCons.Util.RegError, IntelCError): + topdir = None + + if not topdir: + # Normally this is an error, but it might not be if the compiler is + # on $PATH and the user is importing their env. + class ICLTopDirWarning(SCons.Warnings.Warning): + pass + if (is_mac or is_linux) and not env.Detect('icc') or \ + is_windows and not env.Detect('icl'): + + SCons.Warnings.enableWarningClass(ICLTopDirWarning) + SCons.Warnings.warn(ICLTopDirWarning, + "Failed to find Intel compiler for version='%s', abi='%s'"% + (str(version), str(abi))) + else: + # should be cleaned up to say what this other version is + # since in this case we have some other Intel compiler installed + SCons.Warnings.enableWarningClass(ICLTopDirWarning) + SCons.Warnings.warn(ICLTopDirWarning, + "Can't find Intel compiler top dir for version='%s', abi='%s'"% + (str(version), str(abi))) + + if topdir: + archdir={'x86_64': 'intel64', + 'amd64' : 'intel64', + 'em64t' : 'intel64', + 'x86' : 'ia32', + 'i386' : 'ia32', + 'ia32' : 'ia32' + }[abi] # for v11 and greater + if os.path.exists(os.path.join(topdir, 'bin', archdir)): + bindir="bin/%s"%archdir + libdir="lib/%s"%archdir + else: + bindir="bin" + libdir="lib" + if verbose: + print("Intel C compiler: using version %s (%g), abi %s, in '%s/%s'"%\ + (repr(version), linux_ver_normalize(version),abi,topdir,bindir)) + if is_linux: + # Show the actual compiler version by running the compiler. + os.system('%s/%s/icc --version'%(topdir,bindir)) + if is_mac: + # Show the actual compiler version by running the compiler. + os.system('%s/%s/icc --version'%(topdir,bindir)) + + env['INTEL_C_COMPILER_TOP'] = topdir + if is_linux: + paths={'INCLUDE' : 'include', + 'LIB' : libdir, + 'PATH' : bindir, + 'LD_LIBRARY_PATH' : libdir} + for p in list(paths.keys()): + env.PrependENVPath(p, os.path.join(topdir, paths[p])) + if is_mac: + paths={'INCLUDE' : 'include', + 'LIB' : libdir, + 'PATH' : bindir, + 'LD_LIBRARY_PATH' : libdir} + for p in list(paths.keys()): + env.PrependENVPath(p, os.path.join(topdir, paths[p])) + if is_windows: + # env key reg valname default subdir of top + paths=(('INCLUDE', 'IncludeDir', 'Include'), + ('LIB' , 'LibDir', 'Lib'), + ('PATH' , 'BinDir', 'Bin')) + # We are supposed to ignore version if topdir is set, so set + # it to the emptry string if it's not already set. + if version is None: + version = '' + # Each path has a registry entry, use that or default to subdir + for p in paths: + try: + path=get_intel_registry_value(p[1], version, abi) + # These paths may have $(ICInstallDir) + # which needs to be substituted with the topdir. + path=path.replace('$(ICInstallDir)', topdir + os.sep) + except IntelCError: + # Couldn't get it from registry: use default subdir of topdir + env.PrependENVPath(p[0], os.path.join(topdir, p[2])) + else: + env.PrependENVPath(p[0], path.split(os.pathsep)) + # print "ICL %s: %s, final=%s"%(p[0], path, str(env['ENV'][p[0]])) + + if is_windows: + env['CC'] = 'icl' + env['CXX'] = 'icl' + env['LINK'] = 'xilink' + else: + env['CC'] = 'icc' + env['CXX'] = 'icpc' + # Don't reset LINK here; + # use smart_link which should already be here from link.py. + #env['LINK'] = '$CC' + env['AR'] = 'xiar' + env['LD'] = 'xild' # not used by default + + # This is not the exact (detailed) compiler version, + # just the major version as determined above or specified + # by the user. It is a float like 80 or 90, in normalized form for Linux + # (i.e. even for Linux 9.0 compiler, still returns 90 rather than 9.0) + if version: + env['INTEL_C_COMPILER_VERSION']=linux_ver_normalize(version) + + if is_windows: + # Look for license file dir + # in system environment, registry, and default location. + envlicdir = os.environ.get("INTEL_LICENSE_FILE", '') + K = ('SOFTWARE\Intel\Licenses') + try: + k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, K) + reglicdir = SCons.Util.RegQueryValueEx(k, "w_cpp")[0] + except (AttributeError, SCons.Util.RegError): + reglicdir = "" + defaultlicdir = r'C:\Program Files\Common Files\Intel\Licenses' + + licdir = None + for ld in [envlicdir, reglicdir]: + # If the string contains an '@', then assume it's a network + # license (port@system) and good by definition. + if ld and (ld.find('@') != -1 or os.path.exists(ld)): + licdir = ld + break + if not licdir: + licdir = defaultlicdir + if not os.path.exists(licdir): + class ICLLicenseDirWarning(SCons.Warnings.Warning): + pass + SCons.Warnings.enableWarningClass(ICLLicenseDirWarning) + SCons.Warnings.warn(ICLLicenseDirWarning, + "Intel license dir was not found." + " Tried using the INTEL_LICENSE_FILE environment variable (%s), the registry (%s) and the default path (%s)." + " Using the default path as a last resort." + % (envlicdir, reglicdir, defaultlicdir)) + env['ENV']['INTEL_LICENSE_FILE'] = licdir + +def exists(env): + if not (is_mac or is_linux or is_windows): + # can't handle this platform + return 0 + + try: + versions = get_all_compiler_versions() + except (SCons.Util.RegError, IntelCError): + versions = None + detected = versions is not None and len(versions) > 0 + if not detected: + # try env.Detect, maybe that will work + if is_windows: + return env.Detect('icl') + elif is_linux: + return env.Detect('icc') + elif is_mac: + return env.Detect('icc') + return detected + +# end of file + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/ipkg.py b/tools/scons/scons-local-3.0.5/SCons/Tool/ipkg.py new file mode 100755 index 0000000000..0027781fb2 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/ipkg.py @@ -0,0 +1,73 @@ +"""SCons.Tool.ipkg + +Tool-specific initialization for ipkg. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +The ipkg tool calls the ipkg-build. Its only argument should be the +packages fake_root. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/ipkg.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os + +import SCons.Builder + +def generate(env): + """Add Builders and construction variables for ipkg to an Environment.""" + try: + bld = env['BUILDERS']['Ipkg'] + except KeyError: + bld = SCons.Builder.Builder(action='$IPKGCOM', + suffix='$IPKGSUFFIX', + source_scanner=None, + target_scanner=None) + env['BUILDERS']['Ipkg'] = bld + + + env['IPKG'] = 'ipkg-build' + env['IPKGCOM'] = '$IPKG $IPKGFLAGS ${SOURCE}' + + if env.WhereIs('id'): + env['IPKGUSER'] = os.popen('id -un').read().strip() + env['IPKGGROUP'] = os.popen('id -gn').read().strip() + env['IPKGFLAGS'] = SCons.Util.CLVar('-o $IPKGUSER -g $IPKGGROUP') + env['IPKGSUFFIX'] = '.ipk' + +def exists(env): + """ + Can we find the tool + """ + return env.Detect('ipkg-build') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/jar.py b/tools/scons/scons-local-3.0.5/SCons/Tool/jar.py new file mode 100755 index 0000000000..4d686af83d --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/jar.py @@ -0,0 +1,241 @@ +"""SCons.Tool.jar + +Tool-specific initialization for jar. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/jar.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" +import os + +import SCons.Subst +import SCons.Util +from SCons.Node.FS import _my_normcase +from SCons.Tool.JavaCommon import get_java_install_dirs + + +def jarSources(target, source, env, for_signature): + """Only include sources that are not a manifest file.""" + try: + env['JARCHDIR'] + except KeyError: + jarchdir_set = False + else: + jarchdir_set = True + jarchdir = env.subst('$JARCHDIR', target=target, source=source) + if jarchdir: + jarchdir = env.fs.Dir(jarchdir) + result = [] + for src in source: + contents = src.get_text_contents() + if not contents.startswith("Manifest-Version"): + if jarchdir_set: + _chdir = jarchdir + else: + try: + _chdir = src.attributes.java_classdir + except AttributeError: + _chdir = None + if _chdir: + # If we are changing the dir with -C, then sources should + # be relative to that directory. + src = SCons.Subst.Literal(src.get_path(_chdir)) + result.append('-C') + result.append(_chdir) + result.append(src) + return result + +def jarManifest(target, source, env, for_signature): + """Look in sources for a manifest file, if any.""" + for src in source: + contents = src.get_text_contents() + if contents.startswith("Manifest-Version"): + return src + return '' + +def jarFlags(target, source, env, for_signature): + """If we have a manifest, make sure that the 'm' + flag is specified.""" + jarflags = env.subst('$JARFLAGS', target=target, source=source) + for src in source: + contents = src.get_text_contents() + if contents.startswith("Manifest-Version"): + if not 'm' in jarflags: + return jarflags + 'm' + break + return jarflags + +def Jar(env, target = None, source = [], *args, **kw): + """ + A pseudo-Builder wrapper around the separate Jar sources{File,Dir} + Builders. + """ + + # jar target should not be a list so assume they passed + # no target and want implicit target to be made and the arg + # was actaully the list of sources + if SCons.Util.is_List(target) and source == []: + SCons.Warnings.Warning("Making implicit target jar file, " + + "and treating the list as sources") + source = target + target = None + + # mutiple targets pass so build each target the same from the + # same source + #TODO Maybe this should only be done once, and the result copied + # for each target since it should result in the same? + if SCons.Util.is_List(target) and SCons.Util.is_List(source): + jars = [] + for single_target in target: + jars += env.Jar( target = single_target, source = source, *args, **kw) + return jars + + # they passed no target so make a target implicitly + if target is None: + try: + # make target from the first source file + target = os.path.splitext(str(source[0]))[0] + env.subst('$JARSUFFIX') + except: + # something strange is happening but attempt anyways + SCons.Warnings.Warning("Could not make implicit target from sources, using directory") + target = os.path.basename(str(env.Dir('.'))) + env.subst('$JARSUFFIX') + + # make lists out of our target and sources + if not SCons.Util.is_List(target): + target = [target] + if not SCons.Util.is_List(source): + source = [source] + + # setup for checking through all the sources and handle accordingly + java_class_suffix = env.subst('$JAVACLASSSUFFIX') + java_suffix = env.subst('$JAVASUFFIX') + target_nodes = [] + + # function for determining what to do with a file and not a directory + # if its already a class file then it can be used as a + # source for jar, otherwise turn it into a class file then + # return the source + def file_to_class(s): + if _my_normcase(str(s)).endswith(java_suffix): + return env.JavaClassFile(source = s, *args, **kw) + else: + return [env.fs.File(s)] + + # function for calling the JavaClassDir builder if a directory is + # passed as a source to Jar builder. The JavaClassDir builder will + # return an empty list if there were not target classes built from + # the directory, in this case assume the user wanted the directory + # copied into the jar as is (it contains other files such as + # resources or class files compiled from proir commands) + # TODO: investigate the expexcted behavior for directories that + # have mixed content, such as Java files along side other files + # files. + def dir_to_class(s): + dir_targets = env.JavaClassDir(source = s, *args, **kw) + if(dir_targets == []): + # no classes files could be built from the source dir + # so pass the dir as is. + return [env.fs.Dir(s)] + else: + return dir_targets + + # loop through the sources and handle each accordingly + # the goal here is to get all the source files into a class + # file or a directory that contains class files + for s in SCons.Util.flatten(source): + s = env.subst(s) + if isinstance(s, SCons.Node.FS.Base): + if isinstance(s, SCons.Node.FS.File): + # found a file so make sure its a class file + target_nodes.extend(file_to_class(s)) + else: + # found a dir so get the class files out of it + target_nodes.extend(dir_to_class(s)) + else: + try: + # source is string try to convert it to file + target_nodes.extend(file_to_class(env.fs.File(s))) + continue + except: + pass + + try: + # source is string try to covnert it to dir + target_nodes.extend(dir_to_class(env.fs.Dir(s))) + continue + except: + pass + + SCons.Warnings.Warning("File: " + str(s) + " could not be identified as File or Directory, skipping.") + + # at this point all our sources have been converted to classes or directories of class + # so pass it to the Jar builder + return env.JarFile(target = target, source = target_nodes, *args, **kw) + +def generate(env): + """Add Builders and construction variables for jar to an Environment.""" + SCons.Tool.CreateJarBuilder(env) + + SCons.Tool.CreateJavaFileBuilder(env) + SCons.Tool.CreateJavaClassFileBuilder(env) + SCons.Tool.CreateJavaClassDirBuilder(env) + + env.AddMethod(Jar) + + if env['PLATFORM'] == 'win32': + # Ensure that we have a proper path for clang + jar = SCons.Tool.find_program_path(env, 'jar', + default_paths=get_java_install_dirs(env['PLATFORM'])) + if jar: + jar_bin_dir = os.path.dirname(jar) + env.AppendENVPath('PATH', jar_bin_dir) + + env['JAR'] = 'jar' + env['JARFLAGS'] = SCons.Util.CLVar('cf') + env['_JARFLAGS'] = jarFlags + env['_JARMANIFEST'] = jarManifest + env['_JARSOURCES'] = jarSources + env['_JARCOM'] = '$JAR $_JARFLAGS $TARGET $_JARMANIFEST $_JARSOURCES' + env['JARCOM'] = "${TEMPFILE('$_JARCOM','$JARCOMSTR')}" + env['JARSUFFIX'] = '.jar' + +def exists(env): + # As reported by Jan Nijtmans in issue #2730, the simple + # return env.Detect('jar') + # doesn't always work during initialization. For now, we + # stop trying to detect an executable (analogous to the + # javac Builder). + # TODO: Come up with a proper detect() routine...and enable it. + return 1 + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/javac.py b/tools/scons/scons-local-3.0.5/SCons/Tool/javac.py new file mode 100755 index 0000000000..a295bfefd8 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/javac.py @@ -0,0 +1,248 @@ +"""SCons.Tool.javac + +Tool-specific initialization for javac. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +__revision__ = "src/engine/SCons/Tool/javac.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os +import os.path +from collections import OrderedDict + +import SCons.Action +import SCons.Builder +from SCons.Node.FS import _my_normcase +from SCons.Tool.JavaCommon import parse_java_file, get_java_install_dirs, get_java_include_paths +import SCons.Util + +def classname(path): + """Turn a string (path name) into a Java class name.""" + return os.path.normpath(path).replace(os.sep, '.') + +def emit_java_classes(target, source, env): + """Create and return lists of source java files + and their corresponding target class files. + """ + java_suffix = env.get('JAVASUFFIX', '.java') + class_suffix = env.get('JAVACLASSSUFFIX', '.class') + + target[0].must_be_same(SCons.Node.FS.Dir) + classdir = target[0] + + s = source[0].rentry().disambiguate() + if isinstance(s, SCons.Node.FS.File): + sourcedir = s.dir.rdir() + elif isinstance(s, SCons.Node.FS.Dir): + sourcedir = s.rdir() + else: + raise SCons.Errors.UserError("Java source must be File or Dir, not '%s'" % s.__class__) + + slist = [] + js = _my_normcase(java_suffix) + for entry in source: + entry = entry.rentry().disambiguate() + if isinstance(entry, SCons.Node.FS.File): + slist.append(entry) + elif isinstance(entry, SCons.Node.FS.Dir): + result = OrderedDict() + dirnode = entry.rdir() + def find_java_files(arg, dirpath, filenames): + java_files = sorted([n for n in filenames + if _my_normcase(n).endswith(js)]) + mydir = dirnode.Dir(dirpath) + java_paths = [mydir.File(f) for f in java_files] + for jp in java_paths: + arg[jp] = True + for dirpath, dirnames, filenames in os.walk(dirnode.get_abspath()): + find_java_files(result, dirpath, filenames) + entry.walk(find_java_files, result) + + slist.extend(list(result.keys())) + else: + raise SCons.Errors.UserError("Java source must be File or Dir, not '%s'" % entry.__class__) + + version = env.get('JAVAVERSION', '1.4') + full_tlist = [] + for f in slist: + tlist = [] + source_file_based = True + pkg_dir = None + if not f.is_derived(): + pkg_dir, classes = parse_java_file(f.rfile().get_abspath(), version) + if classes: + source_file_based = False + if pkg_dir: + d = target[0].Dir(pkg_dir) + p = pkg_dir + os.sep + else: + d = target[0] + p = '' + for c in classes: + t = d.File(c + class_suffix) + t.attributes.java_classdir = classdir + t.attributes.java_sourcedir = sourcedir + t.attributes.java_classname = classname(p + c) + tlist.append(t) + + if source_file_based: + base = f.name[:-len(java_suffix)] + if pkg_dir: + t = target[0].Dir(pkg_dir).File(base + class_suffix) + else: + t = target[0].File(base + class_suffix) + t.attributes.java_classdir = classdir + t.attributes.java_sourcedir = f.dir + t.attributes.java_classname = classname(base) + tlist.append(t) + + for t in tlist: + t.set_specific_source([f]) + + full_tlist.extend(tlist) + + return full_tlist, slist + +JavaAction = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR') + +JavaBuilder = SCons.Builder.Builder(action = JavaAction, + emitter = emit_java_classes, + target_factory = SCons.Node.FS.Entry, + source_factory = SCons.Node.FS.Entry) + +class pathopt(object): + """ + Callable object for generating javac-style path options from + a construction variable (e.g. -classpath, -sourcepath). + """ + def __init__(self, opt, var, default=None): + self.opt = opt + self.var = var + self.default = default + + def __call__(self, target, source, env, for_signature): + path = env[self.var] + if path and not SCons.Util.is_List(path): + path = [path] + if self.default: + default = env[self.default] + if default: + if not SCons.Util.is_List(default): + default = [default] + path = path + default + if path: + return [self.opt, os.pathsep.join(map(str, path))] + else: + return [] + +def Java(env, target, source, *args, **kw): + """ + A pseudo-Builder wrapper around the separate JavaClass{File,Dir} + Builders. + """ + if not SCons.Util.is_List(target): + target = [target] + if not SCons.Util.is_List(source): + source = [source] + + # Pad the target list with repetitions of the last element in the + # list so we have a target for every source element. + target = target + ([target[-1]] * (len(source) - len(target))) + + java_suffix = env.subst('$JAVASUFFIX') + result = [] + + for t, s in zip(target, source): + if isinstance(s, SCons.Node.FS.Base): + if isinstance(s, SCons.Node.FS.File): + b = env.JavaClassFile + else: + b = env.JavaClassDir + else: + if os.path.isfile(s): + b = env.JavaClassFile + elif os.path.isdir(s): + b = env.JavaClassDir + elif s[-len(java_suffix):] == java_suffix: + b = env.JavaClassFile + else: + b = env.JavaClassDir + result.extend(b(t, s, *args, **kw)) + + return result + +def generate(env): + """Add Builders and construction variables for javac to an Environment.""" + java_file = SCons.Tool.CreateJavaFileBuilder(env) + java_class = SCons.Tool.CreateJavaClassFileBuilder(env) + java_class_dir = SCons.Tool.CreateJavaClassDirBuilder(env) + java_class.add_emitter(None, emit_java_classes) + java_class.add_emitter(env.subst('$JAVASUFFIX'), emit_java_classes) + java_class_dir.emitter = emit_java_classes + + env.AddMethod(Java) + + version = env.get('JAVAVERSION', None) + + javac = SCons.Tool.find_program_path(env, 'javac') + if env['PLATFORM'] == 'win32': + # Ensure that we have a proper path for javac + paths=get_java_install_dirs(env['PLATFORM'], version=version) + javac = SCons.Tool.find_program_path(env, 'javac', + default_paths=paths) + if javac: + javac_bin_dir = os.path.dirname(javac) + env.AppendENVPath('PATH', javac_bin_dir) + + env['JAVAINCLUDES'] = get_java_include_paths(env, javac, version) + + + env['JAVAC'] = 'javac' + env['JAVACFLAGS'] = SCons.Util.CLVar('') + env['JAVABOOTCLASSPATH'] = [] + env['JAVACLASSPATH'] = [] + env['JAVASOURCEPATH'] = [] + env['_javapathopt'] = pathopt + env['_JAVABOOTCLASSPATH'] = '${_javapathopt("-bootclasspath", "JAVABOOTCLASSPATH")} ' + env['_JAVACLASSPATH'] = '${_javapathopt("-classpath", "JAVACLASSPATH")} ' + env['_JAVASOURCEPATH'] = '${_javapathopt("-sourcepath", "JAVASOURCEPATH", "_JAVASOURCEPATHDEFAULT")} ' + env['_JAVASOURCEPATHDEFAULT'] = '${TARGET.attributes.java_sourcedir}' + env['_JAVACCOM'] = '$JAVAC $JAVACFLAGS $_JAVABOOTCLASSPATH $_JAVACLASSPATH -d ${TARGET.attributes.java_classdir} $_JAVASOURCEPATH $SOURCES' + env['JAVACCOM'] = "${TEMPFILE('$_JAVACCOM','$JAVACCOMSTR')}" + env['JAVACLASSSUFFIX'] = '.class' + env['JAVASUFFIX'] = '.java' + +def exists(env): + return 1 + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/javah.py b/tools/scons/scons-local-3.0.5/SCons/Tool/javah.py new file mode 100755 index 0000000000..791c7ab425 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/javah.py @@ -0,0 +1,147 @@ +"""SCons.Tool.javah + +Tool-specific initialization for javah. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/javah.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os.path + +import SCons.Action +import SCons.Builder +import SCons.Node.FS +import SCons.Tool.javac +import SCons.Util +from SCons.Tool.JavaCommon import get_java_install_dirs + + +def emit_java_headers(target, source, env): + """Create and return lists of Java stub header files that will + be created from a set of class files. + """ + class_suffix = env.get('JAVACLASSSUFFIX', '.class') + classdir = env.get('JAVACLASSDIR') + + if not classdir: + try: + s = source[0] + except IndexError: + classdir = '.' + else: + try: + classdir = s.attributes.java_classdir + except AttributeError: + classdir = '.' + classdir = env.Dir(classdir).rdir() + + if str(classdir) == '.': + c_ = None + else: + c_ = str(classdir) + os.sep + + slist = [] + for src in source: + try: + classname = src.attributes.java_classname + except AttributeError: + classname = str(src) + if c_ and classname[:len(c_)] == c_: + classname = classname[len(c_):] + if class_suffix and classname[-len(class_suffix):] == class_suffix: + classname = classname[:-len(class_suffix)] + classname = SCons.Tool.javac.classname(classname) + s = src.rfile() + s.attributes.java_classname = classname + slist.append(s) + + s = source[0].rfile() + if not hasattr(s.attributes, 'java_classdir'): + s.attributes.java_classdir = classdir + + if target[0].__class__ is SCons.Node.FS.File: + tlist = target + else: + if not isinstance(target[0], SCons.Node.FS.Dir): + target[0].__class__ = SCons.Node.FS.Dir + target[0]._morph() + tlist = [] + for s in source: + fname = s.attributes.java_classname.replace('.', '_') + '.h' + t = target[0].File(fname) + t.attributes.java_lookupdir = target[0] + tlist.append(t) + + return tlist, source + +def JavaHOutFlagGenerator(target, source, env, for_signature): + try: + t = target[0] + except (AttributeError, IndexError, TypeError): + t = target + try: + return '-d ' + str(t.attributes.java_lookupdir) + except AttributeError: + return '-o ' + str(t) + +def getJavaHClassPath(env,target, source, for_signature): + path = "${SOURCE.attributes.java_classdir}" + if 'JAVACLASSPATH' in env and env['JAVACLASSPATH']: + path = SCons.Util.AppendPath(path, env['JAVACLASSPATH']) + return "-classpath %s" % (path) + +def generate(env): + """Add Builders and construction variables for javah to an Environment.""" + java_javah = SCons.Tool.CreateJavaHBuilder(env) + java_javah.emitter = emit_java_headers + + if env['PLATFORM'] == 'win32': + # Ensure that we have a proper path for clang + javah = SCons.Tool.find_program_path(env, 'javah', + default_paths=get_java_install_dirs(env['PLATFORM'])) + if javah: + javah_bin_dir = os.path.dirname(javah) + env.AppendENVPath('PATH', javah_bin_dir) + + env['_JAVAHOUTFLAG'] = JavaHOutFlagGenerator + env['JAVAH'] = 'javah' + env['JAVAHFLAGS'] = SCons.Util.CLVar('') + env['_JAVAHCLASSPATH'] = getJavaHClassPath + env['JAVAHCOM'] = '$JAVAH $JAVAHFLAGS $_JAVAHOUTFLAG $_JAVAHCLASSPATH ${SOURCES.attributes.java_classname}' + env['JAVACLASSSUFFIX'] = '.class' + +def exists(env): + return env.Detect('javah') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/latex.py b/tools/scons/scons-local-3.0.5/SCons/Tool/latex.py new file mode 100755 index 0000000000..008a98a27b --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/latex.py @@ -0,0 +1,80 @@ +"""SCons.Tool.latex + +Tool-specific initialization for LaTeX. +Generates .dvi files from .latex or .ltx files + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/latex.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Action +import SCons.Defaults +import SCons.Scanner.LaTeX +import SCons.Util +import SCons.Tool +import SCons.Tool.tex + +def LaTeXAuxFunction(target = None, source= None, env=None): + result = SCons.Tool.tex.InternalLaTeXAuxAction( SCons.Tool.tex.LaTeXAction, target, source, env ) + if result != 0: + SCons.Tool.tex.check_file_error_message(env['LATEX']) + return result + +LaTeXAuxAction = SCons.Action.Action(LaTeXAuxFunction, + strfunction=SCons.Tool.tex.TeXLaTeXStrFunction) + +def generate(env): + """Add Builders and construction variables for LaTeX to an Environment.""" + + env.AppendUnique(LATEXSUFFIXES=SCons.Tool.LaTeXSuffixes) + + from . import dvi + dvi.generate(env) + + from . import pdf + pdf.generate(env) + + bld = env['BUILDERS']['DVI'] + bld.add_action('.ltx', LaTeXAuxAction) + bld.add_action('.latex', LaTeXAuxAction) + bld.add_emitter('.ltx', SCons.Tool.tex.tex_eps_emitter) + bld.add_emitter('.latex', SCons.Tool.tex.tex_eps_emitter) + + SCons.Tool.tex.generate_common(env) + +def exists(env): + SCons.Tool.tex.generate_darwin(env) + return env.Detect('latex') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/ldc.py b/tools/scons/scons-local-3.0.5/SCons/Tool/ldc.py new file mode 100755 index 0000000000..c2e9a8f43b --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/ldc.py @@ -0,0 +1,158 @@ +from __future__ import print_function + +"""SCons.Tool.ldc + +Tool-specific initialization for the LDC compiler. +(https://github.com/ldc-developers/ldc) + +Developed by Russel Winder (russel@winder.org.uk) +2012-05-09 onwards + +Compiler variables: + DC - The name of the D compiler to use. Defaults to ldc2. + DPATH - List of paths to search for import modules. + DVERSIONS - List of version tags to enable when compiling. + DDEBUG - List of debug tags to enable when compiling. + +Linker related variables: + LIBS - List of library files to link in. + DLINK - Name of the linker to use. Defaults to ldc2. + DLINKFLAGS - List of linker flags. + +Lib tool variables: + DLIB - Name of the lib tool to use. Defaults to lib. + DLIBFLAGS - List of flags to pass to the lib tool. + LIBS - Same as for the linker. (libraries to pull into the .lib) +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/ldc.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os +import subprocess + +import SCons.Action +import SCons.Builder +import SCons.Defaults +import SCons.Scanner.D +import SCons.Tool + +import SCons.Tool.DCommon as DCommon + + +def generate(env): + static_obj, shared_obj = SCons.Tool.createObjBuilders(env) + + static_obj.add_action('.d', SCons.Defaults.DAction) + shared_obj.add_action('.d', SCons.Defaults.ShDAction) + static_obj.add_emitter('.d', SCons.Defaults.StaticObjectEmitter) + shared_obj.add_emitter('.d', SCons.Defaults.SharedObjectEmitter) + + env['DC'] = env.Detect('ldc2') or 'ldc2' + env['DCOM'] = '$DC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -c -of=$TARGET $SOURCES' + env['_DINCFLAGS'] = '${_concat(DINCPREFIX, DPATH, DINCSUFFIX, __env__, RDirs, TARGET, SOURCE)}' + env['_DVERFLAGS'] = '${_concat(DVERPREFIX, DVERSIONS, DVERSUFFIX, __env__)}' + env['_DDEBUGFLAGS'] = '${_concat(DDEBUGPREFIX, DDEBUG, DDEBUGSUFFIX, __env__)}' + env['_DFLAGS'] = '${_concat(DFLAGPREFIX, DFLAGS, DFLAGSUFFIX, __env__)}' + + env['SHDC'] = '$DC' + env['SHDCOM'] = '$DC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -c -relocation-model=pic -of=$TARGET $SOURCES' + + env['DPATH'] = ['#/'] + env['DFLAGS'] = [] + env['DVERSIONS'] = [] + env['DDEBUG'] = [] + + if env['DC']: + DCommon.addDPATHToEnv(env, env['DC']) + + env['DINCPREFIX'] = '-I=' + env['DINCSUFFIX'] = '' + env['DVERPREFIX'] = '-version=' + env['DVERSUFFIX'] = '' + env['DDEBUGPREFIX'] = '-debug=' + env['DDEBUGSUFFIX'] = '' + env['DFLAGPREFIX'] = '-' + env['DFLAGSUFFIX'] = '' + env['DFILESUFFIX'] = '.d' + + env['DLINK'] = '$DC' + env['DLINKFLAGS'] = SCons.Util.CLVar('') + env['DLINKCOM'] = '$DLINK -of=$TARGET $DLINKFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS' + + env['SHDLINK'] = '$DC' + env['SHDLINKFLAGS'] = SCons.Util.CLVar('$DLINKFLAGS -shared -defaultlib=phobos2-ldc') + + env['SHDLINKCOM'] = '$DLINK -of=$TARGET $SHDLINKFLAGS $__SHDLIBVERSIONFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS -L-ldruntime-ldc' + + env['DLIBLINKPREFIX'] = '' if env['PLATFORM'] == 'win32' else '-L-l' + env['DLIBLINKSUFFIX'] = '.lib' if env['PLATFORM'] == 'win32' else '' + # env['_DLIBFLAGS'] = '${_concat(DLIBLINKPREFIX, LIBS, DLIBLINKSUFFIX, __env__, RDirs, TARGET, SOURCE)}' + env['_DLIBFLAGS'] = '${_stripixes(DLIBLINKPREFIX, LIBS, DLIBLINKSUFFIX, LIBPREFIXES, LIBSUFFIXES, __env__)}' + + env['DLIBDIRPREFIX'] = '-L-L' + env['DLIBDIRSUFFIX'] = '' + env['_DLIBDIRFLAGS'] = '${_concat(DLIBDIRPREFIX, LIBPATH, DLIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)}' + + env['DLIB'] = 'lib' if env['PLATFORM'] == 'win32' else 'ar cr' + env['DLIBCOM'] = '$DLIB $_DLIBFLAGS {0}$TARGET $SOURCES $_DLIBFLAGS'.format('-c ' if env['PLATFORM'] == 'win32' else '') + + # env['_DLIBFLAGS'] = '${_concat(DLIBFLAGPREFIX, DLIBFLAGS, DLIBFLAGSUFFIX, __env__)}' + + env['DLIBFLAGPREFIX'] = '-' + env['DLIBFLAGSUFFIX'] = '' + + # __RPATH is set to $_RPATH in the platform specification if that + # platform supports it. + env['DRPATHPREFIX'] = '-L-Wl,-rpath,' if env['PLATFORM'] == 'darwin' else '-L-rpath=' + env['DRPATHSUFFIX'] = '' + env['_DRPATH'] = '${_concat(DRPATHPREFIX, RPATH, DRPATHSUFFIX, __env__)}' + + # Support for versioned libraries + env['_SHDLIBVERSIONFLAGS'] = '$SHDLIBVERSIONFLAGS -L-soname=$_SHDLIBSONAME' + env['_SHDLIBSONAME'] = '${DShLibSonameGenerator(__env__,TARGET)}' + # NOTE: this is a quick hack, the soname will only work if there is + # c/c++ linker loaded which provides callback for the ShLibSonameGenerator + env['DShLibSonameGenerator'] = SCons.Tool.ShLibSonameGenerator + # NOTE: this is only for further reference, currently $SHDLIBVERSION does + # not work, the user must use $SHLIBVERSION + env['SHDLIBVERSION'] = '$SHLIBVERSION' + env['SHDLIBVERSIONFLAGS'] = [] + + env['BUILDERS']['ProgramAllAtOnce'] = SCons.Builder.Builder( + action='$DC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -of=$TARGET $DLINKFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS', + emitter=DCommon.allAtOnceEmitter, + ) + + +def exists(env): + return env.Detect('ldc2') + + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/lex.py b/tools/scons/scons-local-3.0.5/SCons/Tool/lex.py new file mode 100755 index 0000000000..fc6322f532 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/lex.py @@ -0,0 +1,135 @@ +"""SCons.Tool.lex + +Tool-specific initialization for lex. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/lex.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os.path +import sys + +import SCons.Action +import SCons.Tool +import SCons.Util +from SCons.Platform.mingw import MINGW_DEFAULT_PATHS +from SCons.Platform.cygwin import CYGWIN_DEFAULT_PATHS +from SCons.Platform.win32 import CHOCO_DEFAULT_PATH + +LexAction = SCons.Action.Action("$LEXCOM", "$LEXCOMSTR") + +def lexEmitter(target, source, env): + sourceBase, sourceExt = os.path.splitext(SCons.Util.to_String(source[0])) + + if sourceExt == ".lm": # If using Objective-C + target = [sourceBase + ".m"] # the extension is ".m". + + # This emitter essentially tries to add to the target all extra + # files generated by flex. + + # Different options that are used to trigger the creation of extra files. + fileGenOptions = ["--header-file=", "--tables-file="] + + lexflags = env.subst("$LEXFLAGS", target=target, source=source) + for option in SCons.Util.CLVar(lexflags): + for fileGenOption in fileGenOptions: + l = len(fileGenOption) + if option[:l] == fileGenOption: + # A file generating option is present, so add the + # file name to the target list. + fileName = option[l:].strip() + target.append(fileName) + return (target, source) + +def get_lex_path(env, append_paths=False): + """ + Find the a path containing the lex or flex binaries. If a construction + environment is passed in then append the path to the ENV PATH. + """ + # save existing path to reset if we don't want to append any paths + envPath = env['ENV']['PATH'] + bins = ['flex', 'lex', 'win_flex'] + + for prog in bins: + bin_path = SCons.Tool.find_program_path( + env, + prog, + default_paths=CHOCO_DEFAULT_PATH + MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS ) + if bin_path: + if not append_paths: + env['ENV']['PATH'] = envPath + else: + env.AppendENVPath('PATH', os.path.dirname(bin_path)) + return bin_path + SCons.Warnings.Warning('lex tool requested, but lex or flex binary not found in ENV PATH') + + +def generate(env): + """Add Builders and construction variables for lex to an Environment.""" + c_file, cxx_file = SCons.Tool.createCFileBuilders(env) + + # C + c_file.add_action(".l", LexAction) + c_file.add_emitter(".l", lexEmitter) + + c_file.add_action(".lex", LexAction) + c_file.add_emitter(".lex", lexEmitter) + + # Objective-C + cxx_file.add_action(".lm", LexAction) + cxx_file.add_emitter(".lm", lexEmitter) + + # C++ + cxx_file.add_action(".ll", LexAction) + cxx_file.add_emitter(".ll", lexEmitter) + + env["LEXFLAGS"] = SCons.Util.CLVar("") + + if sys.platform == 'win32': + get_lex_path(env, append_paths=True) + env["LEX"] = env.Detect(['flex', 'lex', 'win_flex']) + if not env.get("LEXUNISTD"): + env["LEXUNISTD"] = SCons.Util.CLVar("") + env["LEXCOM"] = "$LEX $LEXUNISTD $LEXFLAGS -t $SOURCES > $TARGET" + else: + env["LEX"] = env.Detect(["flex", "lex"]) + env["LEXCOM"] = "$LEX $LEXFLAGS -t $SOURCES > $TARGET" + +def exists(env): + if sys.platform == 'win32': + return get_lex_path(env) + else: + return env.Detect(["flex", "lex"]) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/link.py b/tools/scons/scons-local-3.0.5/SCons/Tool/link.py new file mode 100755 index 0000000000..95a00cc0e9 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/link.py @@ -0,0 +1,362 @@ +"""SCons.Tool.link + +Tool-specific initialization for the generic Posix linker. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +from __future__ import print_function + +__revision__ = "src/engine/SCons/Tool/link.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import sys +import re +import os + +import SCons.Tool +import SCons.Util +import SCons.Warnings + +from SCons.Tool.FortranCommon import isfortran + +from SCons.Tool.DCommon import isD + +from SCons.Tool.cxx import iscplusplus + +issued_mixed_link_warning = False + + +def smart_link(source, target, env, for_signature): + has_cplusplus = iscplusplus(source) + has_fortran = isfortran(env, source) + has_d = isD(env, source) + if has_cplusplus and has_fortran and not has_d: + global issued_mixed_link_warning + if not issued_mixed_link_warning: + msg = "Using $CXX to link Fortran and C++ code together.\n\t" + \ + "This may generate a buggy executable if the '%s'\n\t" + \ + "compiler does not know how to deal with Fortran runtimes." + SCons.Warnings.warn(SCons.Warnings.FortranCxxMixWarning, + msg % env.subst('$CXX')) + issued_mixed_link_warning = True + return '$CXX' + elif has_d: + env['LINKCOM'] = env['DLINKCOM'] + env['SHLINKCOM'] = env['SHDLINKCOM'] + return '$DC' + elif has_fortran: + return '$FORTRAN' + elif has_cplusplus: + return '$CXX' + return '$CC' + + +def _lib_emitter(target, source, env, **kw): + Verbose = False + if Verbose: + print("_lib_emitter: target[0]={!r}".format(target[0].get_path())) + for tgt in target: + if SCons.Util.is_String(tgt): + tgt = env.File(tgt) + tgt.attributes.shared = 1 + + try: + symlink_generator = kw['symlink_generator'] + except KeyError: + pass + else: + if Verbose: + print("_lib_emitter: symlink_generator={!r}".format(symlink_generator)) + symlinks = symlink_generator(env, target[0]) + if Verbose: + print("_lib_emitter: symlinks={!r}".format(symlinks)) + + if symlinks: + SCons.Tool.EmitLibSymlinks(env, symlinks, target[0]) + target[0].attributes.shliblinks = symlinks + return (target, source) + + +def shlib_emitter(target, source, env): + return _lib_emitter(target, source, env, symlink_generator=SCons.Tool.ShLibSymlinkGenerator) + + +def ldmod_emitter(target, source, env): + return _lib_emitter(target, source, env, symlink_generator=SCons.Tool.LdModSymlinkGenerator) + + +# This is generic enough to be included here... +def _versioned_lib_name(env, libnode, version, prefix, suffix, prefix_generator, suffix_generator, **kw): + """For libnode='/optional/dir/libfoo.so.X.Y.Z' it returns 'libfoo.so'""" + Verbose = False + + if Verbose: + print("_versioned_lib_name: libnode={!r}".format(libnode.get_path())) + print("_versioned_lib_name: version={!r}".format(version)) + print("_versioned_lib_name: prefix={!r}".format(prefix)) + print("_versioned_lib_name: suffix={!r}".format(suffix)) + print("_versioned_lib_name: suffix_generator={!r}".format(suffix_generator)) + + versioned_name = os.path.basename(libnode.get_path()) + if Verbose: + print("_versioned_lib_name: versioned_name={!r}".format(versioned_name)) + + versioned_prefix = prefix_generator(env, **kw) + versioned_suffix = suffix_generator(env, **kw) + if Verbose: + print("_versioned_lib_name: versioned_prefix={!r}".format(versioned_prefix)) + print("_versioned_lib_name: versioned_suffix={!r}".format(versioned_suffix)) + + versioned_prefix_re = '^' + re.escape(versioned_prefix) + versioned_suffix_re = re.escape(versioned_suffix) + '$' + name = re.sub(versioned_prefix_re, prefix, versioned_name) + name = re.sub(versioned_suffix_re, suffix, name) + if Verbose: + print("_versioned_lib_name: name={!r}".format(name)) + return name + + +def _versioned_shlib_name(env, libnode, version, prefix, suffix, **kw): + prefix_generator = SCons.Tool.ShLibPrefixGenerator + suffix_generator = SCons.Tool.ShLibSuffixGenerator + return _versioned_lib_name(env, libnode, version, prefix, suffix, prefix_generator, suffix_generator, **kw) + + +def _versioned_ldmod_name(env, libnode, version, prefix, suffix, **kw): + prefix_generator = SCons.Tool.LdModPrefixGenerator + suffix_generator = SCons.Tool.LdModSuffixGenerator + return _versioned_lib_name(env, libnode, version, prefix, suffix, prefix_generator, suffix_generator, **kw) + + +def _versioned_lib_suffix(env, suffix, version): + """For suffix='.so' and version='0.1.2' it returns '.so.0.1.2'""" + Verbose = False + if Verbose: + print("_versioned_lib_suffix: suffix={!r}".format(suffix)) + print("_versioned_lib_suffix: version={!r}".format(version)) + if not suffix.endswith(version): + suffix = suffix + '.' + version + if Verbose: + print("_versioned_lib_suffix: return suffix={!r}".format(suffix)) + return suffix + + +def _versioned_lib_soname(env, libnode, version, prefix, suffix, name_func): + """For libnode='/optional/dir/libfoo.so.X.Y.Z' it returns 'libfoo.so.X'""" + Verbose = False + if Verbose: + print("_versioned_lib_soname: version={!r}".format(version)) + name = name_func(env, libnode, version, prefix, suffix) + if Verbose: + print("_versioned_lib_soname: name={!r}".format(name)) + major = version.split('.')[0] + soname = name + '.' + major + if Verbose: + print("_versioned_lib_soname: soname={!r}".format(soname)) + return soname + + +def _versioned_shlib_soname(env, libnode, version, prefix, suffix): + return _versioned_lib_soname(env, libnode, version, prefix, suffix, _versioned_shlib_name) + + +def _versioned_ldmod_soname(env, libnode, version, prefix, suffix): + return _versioned_lib_soname(env, libnode, version, prefix, suffix, _versioned_ldmod_name) + + +def _versioned_lib_symlinks(env, libnode, version, prefix, suffix, name_func, soname_func): + """Generate link names that should be created for a versioned shared library. + Returns a dictionary in the form { linkname : linktarget } + """ + Verbose = False + + if Verbose: + print("_versioned_lib_symlinks: libnode={!r}".format(libnode.get_path())) + print("_versioned_lib_symlinks: version={!r}".format(version)) + + if sys.platform.startswith('openbsd'): + # OpenBSD uses x.y shared library versioning numbering convention + # and doesn't use symlinks to backwards-compatible libraries + if Verbose: + print("_versioned_lib_symlinks: return symlinks={!r}".format(None)) + return None + + linkdir = libnode.get_dir() + if Verbose: + print("_versioned_lib_symlinks: linkdir={!r}".format(linkdir.get_path())) + + name = name_func(env, libnode, version, prefix, suffix) + if Verbose: + print("_versioned_lib_symlinks: name={!r}".format(name)) + + soname = soname_func(env, libnode, version, prefix, suffix) + if Verbose: + print("_versioned_lib_symlinks: soname={!r}".format(soname)) + + link0 = env.fs.File(soname, linkdir) + link1 = env.fs.File(name, linkdir) + + # We create direct symlinks, not daisy-chained. + if link0 == libnode: + # This enables SHLIBVERSION without periods (e.g. SHLIBVERSION=1) + symlinks = [(link1, libnode)] + else: + # This handles usual SHLIBVERSION, i.e. '1.2', '1.2.3', etc. + symlinks = [(link0, libnode), (link1, libnode)] + + if Verbose: + print("_versioned_lib_symlinks: return symlinks={!r}".format(SCons.Tool.StringizeLibSymlinks(symlinks))) + + return symlinks + + +def _versioned_shlib_symlinks(env, libnode, version, prefix, suffix): + name_func = env['LINKCALLBACKS']['VersionedShLibName'] + soname_func = env['LINKCALLBACKS']['VersionedShLibSoname'] + + return _versioned_lib_symlinks(env, libnode, version, prefix, suffix, name_func, soname_func) + + +def _versioned_ldmod_symlinks(env, libnode, version, prefix, suffix): + name_func = _versioned_ldmod_name + soname_func = _versioned_ldmod_soname + + name_func = env['LINKCALLBACKS']['VersionedLdModName'] + soname_func = env['LINKCALLBACKS']['VersionedLdModSoname'] + + return _versioned_lib_symlinks(env, libnode, version, prefix, suffix, name_func, soname_func) + + +def _versioned_lib_callbacks(): + return { + 'VersionedShLibSuffix': _versioned_lib_suffix, + 'VersionedLdModSuffix': _versioned_lib_suffix, + 'VersionedShLibSymlinks': _versioned_shlib_symlinks, + 'VersionedLdModSymlinks': _versioned_ldmod_symlinks, + 'VersionedShLibName': _versioned_shlib_name, + 'VersionedLdModName': _versioned_ldmod_name, + 'VersionedShLibSoname': _versioned_shlib_soname, + 'VersionedLdModSoname': _versioned_ldmod_soname, + }.copy() + + +def _setup_versioned_lib_variables(env, **kw): + """ + Setup all variables required by the versioning machinery + """ + + tool = None + try: + tool = kw['tool'] + except KeyError: + pass + + use_soname = False + try: + use_soname = kw['use_soname'] + except KeyError: + pass + + # The $_SHLIBVERSIONFLAGS define extra commandline flags used when + # building VERSIONED shared libraries. It's always set, but used only + # when VERSIONED library is built (see __SHLIBVERSIONFLAGS in SCons/Defaults.py). + if use_soname: + # If the linker uses SONAME, then we need this little automata + if tool == 'sunlink': + env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS -h $_SHLIBSONAME' + env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS -h $_LDMODULESONAME' + else: + env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS -Wl,-soname=$_SHLIBSONAME' + env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS -Wl,-soname=$_LDMODULESONAME' + env['_SHLIBSONAME'] = '${ShLibSonameGenerator(__env__,TARGET)}' + env['_LDMODULESONAME'] = '${LdModSonameGenerator(__env__,TARGET)}' + env['ShLibSonameGenerator'] = SCons.Tool.ShLibSonameGenerator + env['LdModSonameGenerator'] = SCons.Tool.LdModSonameGenerator + else: + env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS' + env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS' + + # LDOMDULVERSIONFLAGS should always default to $SHLIBVERSIONFLAGS + env['LDMODULEVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS' + + +def generate(env): + """Add Builders and construction variables for gnulink to an Environment.""" + SCons.Tool.createSharedLibBuilder(env) + SCons.Tool.createProgBuilder(env) + + env['SHLINK'] = '$LINK' + env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared') + env['SHLINKCOM'] = '$SHLINK -o $TARGET $SHLINKFLAGS $__SHLIBVERSIONFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS' + + # don't set up the emitter, because AppendUnique will generate a list + # starting with None :-( + env.Append(SHLIBEMITTER=[shlib_emitter]) + + env['SMARTLINK'] = smart_link + env['LINK'] = "$SMARTLINK" + env['LINKFLAGS'] = SCons.Util.CLVar('') + + # __RPATH is only set to something ($_RPATH typically) on platforms that support it. + env['LINKCOM'] = '$LINK -o $TARGET $LINKFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS' + env['LIBDIRPREFIX'] = '-L' + env['LIBDIRSUFFIX'] = '' + env['_LIBFLAGS'] = '${_stripixes(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, LIBPREFIXES, LIBSUFFIXES, __env__)}' + env['LIBLINKPREFIX'] = '-l' + env['LIBLINKSUFFIX'] = '' + + if env['PLATFORM'] == 'hpux': + env['SHLIBSUFFIX'] = '.sl' + elif env['PLATFORM'] == 'aix': + env['SHLIBSUFFIX'] = '.a' + + # For most platforms, a loadable module is the same as a shared + # library. Platforms which are different can override these, but + # setting them the same means that LoadableModule works everywhere. + SCons.Tool.createLoadableModuleBuilder(env) + env['LDMODULE'] = '$SHLINK' + env.Append(LDMODULEEMITTER=[ldmod_emitter]) + env['LDMODULEPREFIX'] = '$SHLIBPREFIX' + env['LDMODULESUFFIX'] = '$SHLIBSUFFIX' + env['LDMODULEFLAGS'] = '$SHLINKFLAGS' + env[ + 'LDMODULECOM'] = '$LDMODULE -o $TARGET $LDMODULEFLAGS $__LDMODULEVERSIONFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS' + env['LDMODULEVERSION'] = '$SHLIBVERSION' + env['LDMODULENOVERSIONSYMLINKS'] = '$SHLIBNOVERSIONSYMLINKS' + + +def exists(env): + # This module isn't really a Tool on its own, it's common logic for + # other linkers. + return None + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/linkloc.py b/tools/scons/scons-local-3.0.5/SCons/Tool/linkloc.py new file mode 100755 index 0000000000..42c180ee64 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/linkloc.py @@ -0,0 +1,113 @@ +"""SCons.Tool.linkloc + +Tool specification for the LinkLoc linker for the Phar Lap ETS embedded +operating system. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/linkloc.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os.path +import re + +import SCons.Action +import SCons.Defaults +import SCons.Errors +import SCons.Tool +import SCons.Util + +from SCons.Tool.MSCommon import msvs_exists, merge_default_version +from SCons.Tool.PharLapCommon import addPharLapPaths + +_re_linker_command = re.compile(r'(\s)@\s*([^\s]+)') + +def repl_linker_command(m): + # Replaces any linker command file directives (e.g. "@foo.lnk") with + # the actual contents of the file. + try: + with open(m.group(2), "r") as f: + return m.group(1) + f.read() + except IOError: + # the linker should return an error if it can't + # find the linker command file so we will remain quiet. + # However, we will replace the @ with a # so we will not continue + # to find it with recursive substitution + return m.group(1) + '#' + m.group(2) + +class LinklocGenerator(object): + def __init__(self, cmdline): + self.cmdline = cmdline + + def __call__(self, env, target, source, for_signature): + if for_signature: + # Expand the contents of any linker command files recursively + subs = 1 + strsub = env.subst(self.cmdline, target=target, source=source) + while subs: + strsub, subs = _re_linker_command.subn(repl_linker_command, strsub) + return strsub + else: + return "${TEMPFILE('" + self.cmdline + "')}" + +def generate(env): + """Add Builders and construction variables for ar to an Environment.""" + SCons.Tool.createSharedLibBuilder(env) + SCons.Tool.createProgBuilder(env) + + env['SUBST_CMD_FILE'] = LinklocGenerator + env['SHLINK'] = '$LINK' + env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS') + env['SHLINKCOM'] = '${SUBST_CMD_FILE("$SHLINK $SHLINKFLAGS $_LIBDIRFLAGS $_LIBFLAGS -dll $TARGET $SOURCES")}' + env['SHLIBEMITTER']= None + env['LDMODULEEMITTER']= None + env['LINK'] = "linkloc" + env['LINKFLAGS'] = SCons.Util.CLVar('') + env['LINKCOM'] = '${SUBST_CMD_FILE("$LINK $LINKFLAGS $_LIBDIRFLAGS $_LIBFLAGS -exe $TARGET $SOURCES")}' + env['LIBDIRPREFIX']='-libpath ' + env['LIBDIRSUFFIX']='' + env['LIBLINKPREFIX']='-lib ' + env['LIBLINKSUFFIX']='$LIBSUFFIX' + + # Set-up ms tools paths for default version + merge_default_version(env) + + addPharLapPaths(env) + +def exists(env): + if msvs_exists(): + return env.Detect('linkloc') + else: + return 0 + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/m4.py b/tools/scons/scons-local-3.0.5/SCons/Tool/m4.py new file mode 100755 index 0000000000..bb27b533bb --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/m4.py @@ -0,0 +1,63 @@ +"""SCons.Tool.m4 + +Tool-specific initialization for m4. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/m4.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Action +import SCons.Builder +import SCons.Util + +def generate(env): + """Add Builders and construction variables for m4 to an Environment.""" + M4Action = SCons.Action.Action('$M4COM', '$M4COMSTR') + bld = SCons.Builder.Builder(action = M4Action, src_suffix = '.m4') + + env['BUILDERS']['M4'] = bld + + # .m4 files might include other files, and it would be pretty hard + # to write a scanner for it, so let's just cd to the dir of the m4 + # file and run from there. + # The src_suffix setup is like so: file.c.m4 -> file.c, + # file.cpp.m4 -> file.cpp etc. + env['M4'] = 'm4' + env['M4FLAGS'] = SCons.Util.CLVar('-E') + env['M4COM'] = 'cd ${SOURCE.rsrcdir} && $M4 $M4FLAGS < ${SOURCE.file} > ${TARGET.abspath}' + +def exists(env): + return env.Detect('m4') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/masm.py b/tools/scons/scons-local-3.0.5/SCons/Tool/masm.py new file mode 100755 index 0000000000..092f5dc356 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/masm.py @@ -0,0 +1,77 @@ +"""SCons.Tool.masm + +Tool-specific initialization for the Microsoft Assembler. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/masm.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Defaults +import SCons.Tool +import SCons.Util + +ASSuffixes = ['.s', '.asm', '.ASM'] +ASPPSuffixes = ['.spp', '.SPP', '.sx'] +if SCons.Util.case_sensitive_suffixes('.s', '.S'): + ASPPSuffixes.extend(['.S']) +else: + ASSuffixes.extend(['.S']) + +def generate(env): + """Add Builders and construction variables for masm to an Environment.""" + static_obj, shared_obj = SCons.Tool.createObjBuilders(env) + + for suffix in ASSuffixes: + static_obj.add_action(suffix, SCons.Defaults.ASAction) + shared_obj.add_action(suffix, SCons.Defaults.ASAction) + static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter) + shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter) + + for suffix in ASPPSuffixes: + static_obj.add_action(suffix, SCons.Defaults.ASPPAction) + shared_obj.add_action(suffix, SCons.Defaults.ASPPAction) + static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter) + shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter) + + env['AS'] = 'ml' + env['ASFLAGS'] = SCons.Util.CLVar('/nologo') + env['ASPPFLAGS'] = '$ASFLAGS' + env['ASCOM'] = '$AS $ASFLAGS /c /Fo$TARGET $SOURCES' + env['ASPPCOM'] = '$CC $ASPPFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c /Fo$TARGET $SOURCES' + env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1 + +def exists(env): + return env.Detect('ml') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/midl.py b/tools/scons/scons-local-3.0.5/SCons/Tool/midl.py new file mode 100755 index 0000000000..2dfd347740 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/midl.py @@ -0,0 +1,88 @@ +"""SCons.Tool.midl + +Tool-specific initialization for midl (Microsoft IDL compiler). + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/midl.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Action +import SCons.Builder +import SCons.Defaults +import SCons.Scanner.IDL +import SCons.Util + +from .MSCommon import msvc_exists + +def midl_emitter(target, source, env): + """Produces a list of outputs from the MIDL compiler""" + base, _ = SCons.Util.splitext(str(target[0])) + tlb = target[0] + incl = base + '.h' + interface = base + '_i.c' + targets = [tlb, incl, interface] + + midlcom = env['MIDLCOM'] + + if midlcom.find('/proxy') != -1: + proxy = base + '_p.c' + targets.append(proxy) + if midlcom.find('/dlldata') != -1: + dlldata = base + '_data.c' + targets.append(dlldata) + + return (targets, source) + +idl_scanner = SCons.Scanner.IDL.IDLScan() + +midl_action = SCons.Action.Action('$MIDLCOM', '$MIDLCOMSTR') + +midl_builder = SCons.Builder.Builder(action = midl_action, + src_suffix = '.idl', + suffix='.tlb', + emitter = midl_emitter, + source_scanner = idl_scanner) + +def generate(env): + """Add Builders and construction variables for midl to an Environment.""" + + env['MIDL'] = 'MIDL.EXE' + env['MIDLFLAGS'] = SCons.Util.CLVar('/nologo') + env['MIDLCOM'] = '$MIDL $MIDLFLAGS /tlb ${TARGETS[0]} /h ${TARGETS[1]} /iid ${TARGETS[2]} /proxy ${TARGETS[3]} /dlldata ${TARGETS[4]} $SOURCE 2> NUL' + env['BUILDERS']['TypeLibrary'] = midl_builder + +def exists(env): + return msvc_exists(env) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/mingw.py b/tools/scons/scons-local-3.0.5/SCons/Tool/mingw.py new file mode 100755 index 0000000000..cb9bc3c5d3 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/mingw.py @@ -0,0 +1,204 @@ +"""SCons.Tool.gcc + +Tool-specific initialization for MinGW (http://www.mingw.org/) + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/mingw.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os +import os.path +import glob + +import SCons.Action +import SCons.Builder +import SCons.Defaults +import SCons.Tool +import SCons.Util + +mingw_paths = [ + r'c:\MinGW\bin', + r'C:\cygwin64\bin', + r'C:\msys64', + r'C:\cygwin\bin', + r'C:\msys', +] + + +def shlib_generator(target, source, env, for_signature): + cmd = SCons.Util.CLVar(['$SHLINK', '$SHLINKFLAGS']) + + dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX') + if dll: cmd.extend(['-o', dll]) + + cmd.extend(['$SOURCES', '$_LIBDIRFLAGS', '$_LIBFLAGS']) + + implib = env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX') + if implib: cmd.append('-Wl,--out-implib,' + implib.get_string(for_signature)) + + def_target = env.FindIxes(target, 'WINDOWSDEFPREFIX', 'WINDOWSDEFSUFFIX') + insert_def = env.subst("$WINDOWS_INSERT_DEF") + if not insert_def in ['', '0', 0] and def_target: \ + cmd.append('-Wl,--output-def,' + def_target.get_string(for_signature)) + + return [cmd] + + +def shlib_emitter(target, source, env): + dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX') + no_import_lib = env.get('no_import_lib', 0) + + if not dll: + raise SCons.Errors.UserError( + "A shared library should have exactly one target with the suffix: %s Target(s) are:%s" % \ + (env.subst("$SHLIBSUFFIX"), ",".join([str(t) for t in target]))) + + if not no_import_lib and \ + not env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX'): + # Create list of target libraries as strings + targetStrings = env.ReplaceIxes(dll, + 'SHLIBPREFIX', 'SHLIBSUFFIX', + 'LIBPREFIX', 'LIBSUFFIX') + + # Now add file nodes to target list + target.append(env.fs.File(targetStrings)) + + # Append a def file target if there isn't already a def file target + # or a def file source or the user has explicitly asked for the target + # to be emitted. + def_source = env.FindIxes(source, 'WINDOWSDEFPREFIX', 'WINDOWSDEFSUFFIX') + def_target = env.FindIxes(target, 'WINDOWSDEFPREFIX', 'WINDOWSDEFSUFFIX') + skip_def_insert = env.subst("$WINDOWS_INSERT_DEF") in ['', '0', 0] + if not def_source and not def_target and not skip_def_insert: + # Create list of target libraries and def files as strings + targetStrings = env.ReplaceIxes(dll, + 'SHLIBPREFIX', 'SHLIBSUFFIX', + 'WINDOWSDEFPREFIX', 'WINDOWSDEFSUFFIX') + + # Now add file nodes to target list + target.append(env.fs.File(targetStrings)) + + return (target, source) + + +shlib_action = SCons.Action.Action(shlib_generator, '$SHLINKCOMSTR', generator=1) +ldmodule_action = SCons.Action.Action(shlib_generator, '$LDMODULECOMSTR', generator=1) + +res_action = SCons.Action.Action('$RCCOM', '$RCCOMSTR') + +res_builder = SCons.Builder.Builder(action=res_action, suffix='.o', + source_scanner=SCons.Tool.SourceFileScanner) +SCons.Tool.SourceFileScanner.add_scanner('.rc', SCons.Defaults.CScan) + +# This is what we search for to find mingw: +# key_program = 'mingw32-gcc' +key_program = 'mingw32-make' + + +def find_version_specific_mingw_paths(): + """ + One example of default mingw install paths is: + C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev2\mingw64\bin + + Use glob'ing to find such and add to mingw_paths + """ + new_paths = glob.glob(r"C:\mingw-w64\*\mingw64\bin") + + return new_paths + + +def generate(env): + global mingw_paths + # Check for reasoanble mingw default paths + mingw_paths += find_version_specific_mingw_paths() + + mingw = SCons.Tool.find_program_path(env, key_program, default_paths=mingw_paths) + if mingw: + mingw_bin_dir = os.path.dirname(mingw) + env.AppendENVPath('PATH', mingw_bin_dir) + + # Most of mingw is the same as gcc and friends... + gnu_tools = ['gcc', 'g++', 'gnulink', 'ar', 'gas', 'gfortran', 'm4'] + for tool in gnu_tools: + SCons.Tool.Tool(tool)(env) + + # ... but a few things differ: + env['CC'] = 'gcc' + # make sure the msvc tool doesnt break us, it added a /flag + if 'CCFLAGS' in env: + # make sure its a CLVar to handle list or str cases + if type(env['CCFLAGS']) is not SCons.Util.CLVar: + env['CCFLAGS'] = SCons.Util.CLVar(env['CCFLAGS']) + env['CCFLAGS'] = SCons.Util.CLVar(str(env['CCFLAGS']).replace('/nologo', '')) + env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS') + env['CXX'] = 'g++' + env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS') + env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared') + env['SHLINKCOM'] = shlib_action + env['LDMODULECOM'] = ldmodule_action + env.Append(SHLIBEMITTER=[shlib_emitter]) + env.Append(LDMODULEEMITTER=[shlib_emitter]) + env['AS'] = 'as' + + env['WIN32DEFPREFIX'] = '' + env['WIN32DEFSUFFIX'] = '.def' + env['WINDOWSDEFPREFIX'] = '${WIN32DEFPREFIX}' + env['WINDOWSDEFSUFFIX'] = '${WIN32DEFSUFFIX}' + + env['SHOBJSUFFIX'] = '.o' + env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1 + env['RC'] = 'windres' + env['RCFLAGS'] = SCons.Util.CLVar('') + env['RCINCFLAGS'] = '$( ${_concat(RCINCPREFIX, CPPPATH, RCINCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)' + env['RCINCPREFIX'] = '--include-dir ' + env['RCINCSUFFIX'] = '' + env['RCCOM'] = '$RC $_CPPDEFFLAGS $RCINCFLAGS ${RCINCPREFIX} ${SOURCE.dir} $RCFLAGS -i $SOURCE -o $TARGET' + env['BUILDERS']['RES'] = res_builder + + # Some setting from the platform also have to be overridden: + env['OBJSUFFIX'] = '.o' + env['LIBPREFIX'] = 'lib' + env['LIBSUFFIX'] = '.a' + env['PROGSUFFIX'] = '.exe' + + +def exists(env): + mingw = SCons.Tool.find_program_path(env, key_program, default_paths=mingw_paths) + if mingw: + mingw_bin_dir = os.path.dirname(mingw) + env.AppendENVPath('PATH', mingw_bin_dir) + + return mingw + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/msgfmt.py b/tools/scons/scons-local-3.0.5/SCons/Tool/msgfmt.py new file mode 100755 index 0000000000..3a73abd16c --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/msgfmt.py @@ -0,0 +1,122 @@ +""" msgfmt tool """ + +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +__revision__ = "src/engine/SCons/Tool/msgfmt.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +from SCons.Builder import BuilderBase +############################################################################# +class _MOFileBuilder(BuilderBase): + """ The builder class for `MO` files. + + The reason for this builder to exists and its purpose is quite simillar + as for `_POFileBuilder`. This time, we extend list of sources, not targets, + and call `BuilderBase._execute()` only once (as we assume single-target + here). + """ + + def _execute(self, env, target, source, *args, **kw): + # Here we add support for 'LINGUAS_FILE' keyword. Emitter is not suitable + # in this case, as it is called too late (after multiple sources + # are handled single_source builder. + import SCons.Util + from SCons.Tool.GettextCommon import _read_linguas_from_files + linguas_files = None + if 'LINGUAS_FILE' in env and env['LINGUAS_FILE'] is not None: + linguas_files = env['LINGUAS_FILE'] + # This should prevent from endless recursion. + env['LINGUAS_FILE'] = None + # We read only languages. Suffixes shall be added automatically. + linguas = _read_linguas_from_files(env, linguas_files) + if SCons.Util.is_List(source): + source.extend(linguas) + elif source is not None: + source = [source] + linguas + else: + source = linguas + result = BuilderBase._execute(self,env,target,source,*args, **kw) + if linguas_files is not None: + env['LINGUAS_FILE'] = linguas_files + return result +############################################################################# + +############################################################################# +def _create_mo_file_builder(env, **kw): + """ Create builder object for `MOFiles` builder """ + import SCons.Action + # FIXME: What factory use for source? Ours or their? + kw['action'] = SCons.Action.Action('$MSGFMTCOM','$MSGFMTCOMSTR') + kw['suffix'] = '$MOSUFFIX' + kw['src_suffix'] = '$POSUFFIX' + kw['src_builder'] = '_POUpdateBuilder' + kw['single_source'] = True + return _MOFileBuilder(**kw) +############################################################################# + +############################################################################# +def generate(env,**kw): + """ Generate `msgfmt` tool """ + import sys + import os + import SCons.Util + import SCons.Tool + from SCons.Tool.GettextCommon import _detect_msgfmt + from SCons.Platform.mingw import MINGW_DEFAULT_PATHS + from SCons.Platform.cygwin import CYGWIN_DEFAULT_PATHS + + if sys.platform == 'win32': + msgfmt = SCons.Tool.find_program_path(env, 'msgfmt', default_paths=MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS ) + if msgfmt: + msgfmt_bin_dir = os.path.dirname(msgfmt) + env.AppendENVPath('PATH', msgfmt_bin_dir) + else: + SCons.Warnings.Warning('msgfmt tool requested, but binary not found in ENV PATH') + + try: + env['MSGFMT'] = _detect_msgfmt(env) + except: + env['MSGFMT'] = 'msgfmt' + env.SetDefault( + MSGFMTFLAGS = [ SCons.Util.CLVar('-c') ], + MSGFMTCOM = '$MSGFMT $MSGFMTFLAGS -o $TARGET $SOURCE', + MSGFMTCOMSTR = '', + MOSUFFIX = ['.mo'], + POSUFFIX = ['.po'] + ) + env.Append( BUILDERS = { 'MOFiles' : _create_mo_file_builder(env) } ) +############################################################################# + +############################################################################# +def exists(env): + """ Check if the tool exists """ + from SCons.Tool.GettextCommon import _msgfmt_exists + try: + return _msgfmt_exists(env) + except: + return False +############################################################################# + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/msginit.py b/tools/scons/scons-local-3.0.5/SCons/Tool/msginit.py new file mode 100755 index 0000000000..5b3dc0be94 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/msginit.py @@ -0,0 +1,134 @@ +""" msginit tool + +Tool specific initialization of msginit tool. +""" + +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +__revision__ = "src/engine/SCons/Tool/msginit.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Warnings +import SCons.Builder +import re + +############################################################################# +def _optional_no_translator_flag(env): + """ Return '--no-translator' flag if we run *msginit(1)* in non-interactive + mode.""" + import SCons.Util + if 'POAUTOINIT' in env: + autoinit = env['POAUTOINIT'] + else: + autoinit = False + if autoinit: + return [SCons.Util.CLVar('--no-translator')] + else: + return [SCons.Util.CLVar('')] +############################################################################# + +############################################################################# +def _POInitBuilder(env, **kw): + """ Create builder object for `POInit` builder. """ + import SCons.Action + from SCons.Tool.GettextCommon import _init_po_files, _POFileBuilder + action = SCons.Action.Action(_init_po_files, None) + return _POFileBuilder(env, action=action, target_alias='$POCREATE_ALIAS') +############################################################################# + +############################################################################# +from SCons.Environment import _null +############################################################################# +def _POInitBuilderWrapper(env, target=None, source=_null, **kw): + """ Wrapper for _POFileBuilder. We use it to make user's life easier. + + This wrapper checks for `$POTDOMAIN` construction variable (or override in + `**kw`) and treats it appropriatelly. + """ + if source is _null: + if 'POTDOMAIN' in kw: + domain = kw['POTDOMAIN'] + elif 'POTDOMAIN' in env: + domain = env['POTDOMAIN'] + else: + domain = 'messages' + source = [ domain ] # NOTE: Suffix shall be appended automatically + return env._POInitBuilder(target, source, **kw) +############################################################################# + +############################################################################# +def generate(env,**kw): + """ Generate the `msginit` tool """ + import sys + import os + import SCons.Util + import SCons.Tool + from SCons.Tool.GettextCommon import _detect_msginit + from SCons.Platform.mingw import MINGW_DEFAULT_PATHS + from SCons.Platform.cygwin import CYGWIN_DEFAULT_PATHS + + if sys.platform == 'win32': + msginit = SCons.Tool.find_program_path(env, 'msginit', default_paths=MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS ) + if msginit: + msginit_bin_dir = os.path.dirname(msginit) + env.AppendENVPath('PATH', msginit_bin_dir) + else: + SCons.Warnings.Warning('msginit tool requested, but binary not found in ENV PATH') + + try: + env['MSGINIT'] = _detect_msginit(env) + except: + env['MSGINIT'] = 'msginit' + msginitcom = '$MSGINIT ${_MSGNoTranslator(__env__)} -l ${_MSGINITLOCALE}' \ + + ' $MSGINITFLAGS -i $SOURCE -o $TARGET' + # NOTE: We set POTSUFFIX here, in case the 'xgettext' is not loaded + # (sometimes we really don't need it) + env.SetDefault( + POSUFFIX = ['.po'], + POTSUFFIX = ['.pot'], + _MSGINITLOCALE = '${TARGET.filebase}', + _MSGNoTranslator = _optional_no_translator_flag, + MSGINITCOM = msginitcom, + MSGINITCOMSTR = '', + MSGINITFLAGS = [ ], + POAUTOINIT = False, + POCREATE_ALIAS = 'po-create' + ) + env.Append( BUILDERS = { '_POInitBuilder' : _POInitBuilder(env) } ) + env.AddMethod(_POInitBuilderWrapper, 'POInit') + env.AlwaysBuild(env.Alias('$POCREATE_ALIAS')) +############################################################################# + +############################################################################# +def exists(env): + """ Check if the tool exists """ + from SCons.Tool.GettextCommon import _msginit_exists + try: + return _msginit_exists(env) + except: + return False +############################################################################# + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/msgmerge.py b/tools/scons/scons-local-3.0.5/SCons/Tool/msgmerge.py new file mode 100755 index 0000000000..c8b7688c0a --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/msgmerge.py @@ -0,0 +1,117 @@ +""" msgmerget tool + +Tool specific initialization for `msgmerge` tool. +""" + +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +__revision__ = "src/engine/SCons/Tool/msgmerge.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +############################################################################# +def _update_or_init_po_files(target, source, env): + """ Action function for `POUpdate` builder """ + import SCons.Action + from SCons.Tool.GettextCommon import _init_po_files + for tgt in target: + if tgt.rexists(): + action = SCons.Action.Action('$MSGMERGECOM', '$MSGMERGECOMSTR') + else: + action = _init_po_files + status = action([tgt], source, env) + if status : return status + return 0 +############################################################################# + +############################################################################# +def _POUpdateBuilder(env, **kw): + """ Create an object of `POUpdate` builder """ + import SCons.Action + from SCons.Tool.GettextCommon import _POFileBuilder + action = SCons.Action.Action(_update_or_init_po_files, None) + return _POFileBuilder(env, action=action, target_alias='$POUPDATE_ALIAS') +############################################################################# + +############################################################################# +from SCons.Environment import _null +############################################################################# +def _POUpdateBuilderWrapper(env, target=None, source=_null, **kw): + """ Wrapper for `POUpdate` builder - make user's life easier """ + if source is _null: + if 'POTDOMAIN' in kw: + domain = kw['POTDOMAIN'] + elif 'POTDOMAIN' in env and env['POTDOMAIN']: + domain = env['POTDOMAIN'] + else: + domain = 'messages' + source = [ domain ] # NOTE: Suffix shall be appended automatically + return env._POUpdateBuilder(target, source, **kw) +############################################################################# + +############################################################################# +def generate(env,**kw): + """ Generate the `msgmerge` tool """ + import sys + import os + import SCons.Tool + from SCons.Tool.GettextCommon import _detect_msgmerge + from SCons.Platform.mingw import MINGW_DEFAULT_PATHS + from SCons.Platform.cygwin import CYGWIN_DEFAULT_PATHS + + if sys.platform == 'win32': + msgmerge = SCons.Tool.find_program_path(env, 'msgmerge', default_paths=MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS ) + if msgmerge: + msgmerge_bin_dir = os.path.dirname(msgmerge) + env.AppendENVPath('PATH', msgmerge_bin_dir) + else: + SCons.Warnings.Warning('msgmerge tool requested, but binary not found in ENV PATH') + try: + env['MSGMERGE'] = _detect_msgmerge(env) + except: + env['MSGMERGE'] = 'msgmerge' + env.SetDefault( + POTSUFFIX = ['.pot'], + POSUFFIX = ['.po'], + MSGMERGECOM = '$MSGMERGE $MSGMERGEFLAGS --update $TARGET $SOURCE', + MSGMERGECOMSTR = '', + MSGMERGEFLAGS = [ ], + POUPDATE_ALIAS = 'po-update' + ) + env.Append(BUILDERS = { '_POUpdateBuilder':_POUpdateBuilder(env) }) + env.AddMethod(_POUpdateBuilderWrapper, 'POUpdate') + env.AlwaysBuild(env.Alias('$POUPDATE_ALIAS')) +############################################################################# + +############################################################################# +def exists(env): + """ Check if the tool exists """ + from SCons.Tool.GettextCommon import _msgmerge_exists + try: + return _msgmerge_exists(env) + except: + return False +############################################################################# + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/mslib.py b/tools/scons/scons-local-3.0.5/SCons/Tool/mslib.py new file mode 100755 index 0000000000..1434773697 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/mslib.py @@ -0,0 +1,64 @@ +"""SCons.Tool.mslib + +Tool-specific initialization for lib (MicroSoft library archiver). + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/mslib.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Defaults +import SCons.Tool +import SCons.Tool.msvs +import SCons.Tool.msvc +import SCons.Util + +from .MSCommon import msvc_exists, msvc_setup_env_once + +def generate(env): + """Add Builders and construction variables for lib to an Environment.""" + SCons.Tool.createStaticLibBuilder(env) + + # Set-up ms tools paths + msvc_setup_env_once(env) + + env['AR'] = 'lib' + env['ARFLAGS'] = SCons.Util.CLVar('/nologo') + env['ARCOM'] = "${TEMPFILE('$AR $ARFLAGS /OUT:$TARGET $SOURCES','$ARCOMSTR')}" + env['LIBPREFIX'] = '' + env['LIBSUFFIX'] = '.lib' + +def exists(env): + return msvc_exists(env) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/mslink.py b/tools/scons/scons-local-3.0.5/SCons/Tool/mslink.py new file mode 100755 index 0000000000..9fd84c7d48 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/mslink.py @@ -0,0 +1,337 @@ +"""SCons.Tool.mslink + +Tool-specific initialization for the Microsoft linker. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +from __future__ import print_function + +__revision__ = "src/engine/SCons/Tool/mslink.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os.path + +import SCons.Action +import SCons.Defaults +import SCons.Errors +import SCons.Platform.win32 +import SCons.Tool +import SCons.Tool.msvc +import SCons.Tool.msvs +import SCons.Util + +from .MSCommon import msvc_setup_env_once, msvc_exists + +def pdbGenerator(env, target, source, for_signature): + try: + return ['/PDB:%s' % target[0].attributes.pdb, '/DEBUG'] + except (AttributeError, IndexError): + return None + +def _dllTargets(target, source, env, for_signature, paramtp): + listCmd = [] + dll = env.FindIxes(target, '%sPREFIX' % paramtp, '%sSUFFIX' % paramtp) + if dll: listCmd.append("/out:%s"%dll.get_string(for_signature)) + + implib = env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX') + if implib: listCmd.append("/implib:%s"%implib.get_string(for_signature)) + + return listCmd + +def _dllSources(target, source, env, for_signature, paramtp): + listCmd = [] + + deffile = env.FindIxes(source, "WINDOWSDEFPREFIX", "WINDOWSDEFSUFFIX") + for src in source: + # Check explicitly for a non-None deffile so that the __cmp__ + # method of the base SCons.Util.Proxy class used for some Node + # proxies doesn't try to use a non-existent __dict__ attribute. + if deffile and src == deffile: + # Treat this source as a .def file. + listCmd.append("/def:%s" % src.get_string(for_signature)) + else: + # Just treat it as a generic source file. + listCmd.append(src) + return listCmd + +def windowsShlinkTargets(target, source, env, for_signature): + return _dllTargets(target, source, env, for_signature, 'SHLIB') + +def windowsShlinkSources(target, source, env, for_signature): + return _dllSources(target, source, env, for_signature, 'SHLIB') + +def _windowsLdmodTargets(target, source, env, for_signature): + """Get targets for loadable modules.""" + return _dllTargets(target, source, env, for_signature, 'LDMODULE') + +def _windowsLdmodSources(target, source, env, for_signature): + """Get sources for loadable modules.""" + return _dllSources(target, source, env, for_signature, 'LDMODULE') + +def _dllEmitter(target, source, env, paramtp): + """Common implementation of dll emitter.""" + SCons.Tool.msvc.validate_vars(env) + + extratargets = [] + extrasources = [] + + dll = env.FindIxes(target, '%sPREFIX' % paramtp, '%sSUFFIX' % paramtp) + no_import_lib = env.get('no_import_lib', 0) + + if not dll: + raise SCons.Errors.UserError('A shared library should have exactly one target with the suffix: %s' % env.subst('$%sSUFFIX' % paramtp)) + + insert_def = env.subst("$WINDOWS_INSERT_DEF") + if not insert_def in ['', '0', 0] and \ + not env.FindIxes(source, "WINDOWSDEFPREFIX", "WINDOWSDEFSUFFIX"): + + # append a def file to the list of sources + extrasources.append( + env.ReplaceIxes(dll, + '%sPREFIX' % paramtp, '%sSUFFIX' % paramtp, + "WINDOWSDEFPREFIX", "WINDOWSDEFSUFFIX")) + + version_num, suite = SCons.Tool.msvs.msvs_parse_version(env.get('MSVS_VERSION', '6.0')) + if version_num >= 8.0 and \ + (env.get('WINDOWS_INSERT_MANIFEST', 0) or env.get('WINDOWS_EMBED_MANIFEST', 0)): + # MSVC 8 and above automatically generate .manifest files that must be installed + extratargets.append( + env.ReplaceIxes(dll, + '%sPREFIX' % paramtp, '%sSUFFIX' % paramtp, + "WINDOWSSHLIBMANIFESTPREFIX", "WINDOWSSHLIBMANIFESTSUFFIX")) + + if 'PDB' in env and env['PDB']: + pdb = env.arg2nodes('$PDB', target=target, source=source)[0] + extratargets.append(pdb) + target[0].attributes.pdb = pdb + + if version_num >= 11.0 and env.get('PCH', 0): + # MSVC 11 and above need the PCH object file to be added to the link line, + # otherwise you get link error LNK2011. + pchobj = SCons.Util.splitext(str(env['PCH']))[0] + '.obj' + # print "prog_emitter, version %s, appending pchobj %s"%(version_num, pchobj) + if pchobj not in extrasources: + extrasources.append(pchobj) + + if not no_import_lib and \ + not env.FindIxes(target, "LIBPREFIX", "LIBSUFFIX"): + # Append an import library to the list of targets. + extratargets.append( + env.ReplaceIxes(dll, + '%sPREFIX' % paramtp, '%sSUFFIX' % paramtp, + "LIBPREFIX", "LIBSUFFIX")) + # and .exp file is created if there are exports from a DLL + extratargets.append( + env.ReplaceIxes(dll, + '%sPREFIX' % paramtp, '%sSUFFIX' % paramtp, + "WINDOWSEXPPREFIX", "WINDOWSEXPSUFFIX")) + + return (target+extratargets, source+extrasources) + +def windowsLibEmitter(target, source, env): + return _dllEmitter(target, source, env, 'SHLIB') + +def ldmodEmitter(target, source, env): + """Emitter for loadable modules. + + Loadable modules are identical to shared libraries on Windows, but building + them is subject to different parameters (LDMODULE*). + """ + return _dllEmitter(target, source, env, 'LDMODULE') + +def prog_emitter(target, source, env): + SCons.Tool.msvc.validate_vars(env) + + extratargets = [] + extrasources = [] + + exe = env.FindIxes(target, "PROGPREFIX", "PROGSUFFIX") + if not exe: + raise SCons.Errors.UserError("An executable should have exactly one target with the suffix: %s" % env.subst("$PROGSUFFIX")) + + version_num, suite = SCons.Tool.msvs.msvs_parse_version(env.get('MSVS_VERSION', '6.0')) + if version_num >= 8.0 and \ + (env.get('WINDOWS_INSERT_MANIFEST', 0) or env.get('WINDOWS_EMBED_MANIFEST', 0)): + # MSVC 8 and above automatically generate .manifest files that have to be installed + extratargets.append( + env.ReplaceIxes(exe, + "PROGPREFIX", "PROGSUFFIX", + "WINDOWSPROGMANIFESTPREFIX", "WINDOWSPROGMANIFESTSUFFIX")) + + if 'PDB' in env and env['PDB']: + pdb = env.arg2nodes('$PDB', target=target, source=source)[0] + extratargets.append(pdb) + target[0].attributes.pdb = pdb + + if version_num >= 11.0 and env.get('PCH', 0): + # MSVC 11 and above need the PCH object file to be added to the link line, + # otherwise you get link error LNK2011. + pchobj = SCons.Util.splitext(str(env['PCH']))[0] + '.obj' + # print("prog_emitter, version %s, appending pchobj %s"%(version_num, pchobj)) + if pchobj not in extrasources: + extrasources.append(pchobj) + + return (target+extratargets,source+extrasources) + +def RegServerFunc(target, source, env): + if 'register' in env and env['register']: + ret = regServerAction([target[0]], [source[0]], env) + if ret: + raise SCons.Errors.UserError("Unable to register %s" % target[0]) + else: + print("Registered %s sucessfully" % target[0]) + return ret + return 0 + +# These are the actual actions run to embed the manifest. +# They are only called from the Check versions below. +embedManifestExeAction = SCons.Action.Action('$MTEXECOM') +embedManifestDllAction = SCons.Action.Action('$MTSHLIBCOM') + +def embedManifestDllCheck(target, source, env): + """Function run by embedManifestDllCheckAction to check for existence of manifest + and other conditions, and embed the manifest by calling embedManifestDllAction if so.""" + if env.get('WINDOWS_EMBED_MANIFEST', 0): + manifestSrc = target[0].get_abspath() + '.manifest' + if os.path.exists(manifestSrc): + ret = (embedManifestDllAction) ([target[0]],None,env) + if ret: + raise SCons.Errors.UserError("Unable to embed manifest into %s" % (target[0])) + return ret + else: + print('(embed: no %s.manifest found; not embedding.)'%str(target[0])) + return 0 + +def embedManifestExeCheck(target, source, env): + """Function run by embedManifestExeCheckAction to check for existence of manifest + and other conditions, and embed the manifest by calling embedManifestExeAction if so.""" + if env.get('WINDOWS_EMBED_MANIFEST', 0): + manifestSrc = target[0].get_abspath() + '.manifest' + if os.path.exists(manifestSrc): + ret = (embedManifestExeAction) ([target[0]],None,env) + if ret: + raise SCons.Errors.UserError("Unable to embed manifest into %s" % (target[0])) + return ret + else: + print('(embed: no %s.manifest found; not embedding.)'%str(target[0])) + return 0 + +embedManifestDllCheckAction = SCons.Action.Action(embedManifestDllCheck, None) +embedManifestExeCheckAction = SCons.Action.Action(embedManifestExeCheck, None) + +regServerAction = SCons.Action.Action("$REGSVRCOM", "$REGSVRCOMSTR") +regServerCheck = SCons.Action.Action(RegServerFunc, None) +shlibLinkAction = SCons.Action.Action('${TEMPFILE("$SHLINK $SHLINKFLAGS $_SHLINK_TARGETS $_LIBDIRFLAGS $_LIBFLAGS $_PDB $_SHLINK_SOURCES", "$SHLINKCOMSTR")}', '$SHLINKCOMSTR') +compositeShLinkAction = shlibLinkAction + regServerCheck + embedManifestDllCheckAction +ldmodLinkAction = SCons.Action.Action('${TEMPFILE("$LDMODULE $LDMODULEFLAGS $_LDMODULE_TARGETS $_LIBDIRFLAGS $_LIBFLAGS $_PDB $_LDMODULE_SOURCES", "$LDMODULECOMSTR")}', '$LDMODULECOMSTR') +compositeLdmodAction = ldmodLinkAction + regServerCheck + embedManifestDllCheckAction +exeLinkAction = SCons.Action.Action('${TEMPFILE("$LINK $LINKFLAGS /OUT:$TARGET.windows $_LIBDIRFLAGS $_LIBFLAGS $_PDB $SOURCES.windows", "$LINKCOMSTR")}', '$LINKCOMSTR') +compositeLinkAction = exeLinkAction + embedManifestExeCheckAction + +def generate(env): + """Add Builders and construction variables for ar to an Environment.""" + SCons.Tool.createSharedLibBuilder(env) + SCons.Tool.createProgBuilder(env) + + env['SHLINK'] = '$LINK' + env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS /dll') + env['_SHLINK_TARGETS'] = windowsShlinkTargets + env['_SHLINK_SOURCES'] = windowsShlinkSources + env['SHLINKCOM'] = compositeShLinkAction + env.Append(SHLIBEMITTER = [windowsLibEmitter]) + env.Append(LDMODULEEMITTER = [windowsLibEmitter]) + env['LINK'] = 'link' + env['LINKFLAGS'] = SCons.Util.CLVar('/nologo') + env['_PDB'] = pdbGenerator + env['LINKCOM'] = compositeLinkAction + env.Append(PROGEMITTER = [prog_emitter]) + env['LIBDIRPREFIX']='/LIBPATH:' + env['LIBDIRSUFFIX']='' + env['LIBLINKPREFIX']='' + env['LIBLINKSUFFIX']='$LIBSUFFIX' + + env['WIN32DEFPREFIX'] = '' + env['WIN32DEFSUFFIX'] = '.def' + env['WIN32_INSERT_DEF'] = 0 + env['WINDOWSDEFPREFIX'] = '${WIN32DEFPREFIX}' + env['WINDOWSDEFSUFFIX'] = '${WIN32DEFSUFFIX}' + env['WINDOWS_INSERT_DEF'] = '${WIN32_INSERT_DEF}' + + env['WIN32EXPPREFIX'] = '' + env['WIN32EXPSUFFIX'] = '.exp' + env['WINDOWSEXPPREFIX'] = '${WIN32EXPPREFIX}' + env['WINDOWSEXPSUFFIX'] = '${WIN32EXPSUFFIX}' + + env['WINDOWSSHLIBMANIFESTPREFIX'] = '' + env['WINDOWSSHLIBMANIFESTSUFFIX'] = '${SHLIBSUFFIX}.manifest' + env['WINDOWSPROGMANIFESTPREFIX'] = '' + env['WINDOWSPROGMANIFESTSUFFIX'] = '${PROGSUFFIX}.manifest' + + env['REGSVRACTION'] = regServerCheck + env['REGSVR'] = os.path.join(SCons.Platform.win32.get_system_root(),'System32','regsvr32') + env['REGSVRFLAGS'] = '/s ' + env['REGSVRCOM'] = '$REGSVR $REGSVRFLAGS ${TARGET.windows}' + + env['WINDOWS_EMBED_MANIFEST'] = 0 + env['MT'] = 'mt' + #env['MTFLAGS'] = ['-hashupdate'] + env['MTFLAGS'] = SCons.Util.CLVar('/nologo') + # Note: use - here to prevent build failure if no manifest produced. + # This seems much simpler than a fancy system using a function action to see + # if the manifest actually exists before trying to run mt with it. + env['MTEXECOM'] = '-$MT $MTFLAGS -manifest ${TARGET}.manifest $_MANIFEST_SOURCES -outputresource:$TARGET;1' + env['MTSHLIBCOM'] = '-$MT $MTFLAGS -manifest ${TARGET}.manifest $_MANIFEST_SOURCES -outputresource:$TARGET;2' + # TODO Future work garyo 27-Feb-11 + env['_MANIFEST_SOURCES'] = None # _windowsManifestSources + + # Set-up ms tools paths + msvc_setup_env_once(env) + + + # Loadable modules are on Windows the same as shared libraries, but they + # are subject to different build parameters (LDMODULE* variables). + # Therefore LDMODULE* variables correspond as much as possible to + # SHLINK*/SHLIB* ones. + SCons.Tool.createLoadableModuleBuilder(env) + env['LDMODULE'] = '$SHLINK' + env['LDMODULEPREFIX'] = '$SHLIBPREFIX' + env['LDMODULESUFFIX'] = '$SHLIBSUFFIX' + env['LDMODULEFLAGS'] = '$SHLINKFLAGS' + env['_LDMODULE_TARGETS'] = _windowsLdmodTargets + env['_LDMODULE_SOURCES'] = _windowsLdmodSources + env['LDMODULEEMITTER'] = [ldmodEmitter] + env['LDMODULECOM'] = compositeLdmodAction + +def exists(env): + return msvc_exists(env) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/mssdk.py b/tools/scons/scons-local-3.0.5/SCons/Tool/mssdk.py new file mode 100755 index 0000000000..1372e87ea8 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/mssdk.py @@ -0,0 +1,50 @@ +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/mssdk.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +"""engine.SCons.Tool.mssdk + +Tool-specific initialization for Microsoft SDKs, both Platform +SDKs and Windows SDKs. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" + +from .MSCommon import mssdk_exists, \ + mssdk_setup_env + +def generate(env): + """Add construction variables for an MS SDK to an Environment.""" + mssdk_setup_env(env) + +def exists(env): + return mssdk_exists() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/msvc.py b/tools/scons/scons-local-3.0.5/SCons/Tool/msvc.py new file mode 100755 index 0000000000..4649963a86 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/msvc.py @@ -0,0 +1,302 @@ +"""engine.SCons.Tool.msvc + +Tool-specific initialization for Microsoft Visual C/C++. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/msvc.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os.path +import re +import sys + +import SCons.Action +import SCons.Builder +import SCons.Errors +import SCons.Platform.win32 +import SCons.Tool +import SCons.Tool.msvs +import SCons.Util +import SCons.Warnings +import SCons.Scanner.RC + +from .MSCommon import msvc_exists, msvc_setup_env_once, msvc_version_to_maj_min + +CSuffixes = ['.c', '.C'] +CXXSuffixes = ['.cc', '.cpp', '.cxx', '.c++', '.C++'] + +def validate_vars(env): + """Validate the PCH and PCHSTOP construction variables.""" + if 'PCH' in env and env['PCH']: + if 'PCHSTOP' not in env: + raise SCons.Errors.UserError("The PCHSTOP construction must be defined if PCH is defined.") + if not SCons.Util.is_String(env['PCHSTOP']): + raise SCons.Errors.UserError("The PCHSTOP construction variable must be a string: %r"%env['PCHSTOP']) + +def msvc_set_PCHPDBFLAGS(env): + """ + Set appropriate PCHPDBFLAGS for the MSVC version being used. + """ + if env.get('MSVC_VERSION',False): + maj, min = msvc_version_to_maj_min(env['MSVC_VERSION']) + if maj < 8: + env['PCHPDBFLAGS'] = SCons.Util.CLVar(['${(PDB and "/Yd") or ""}']) + else: + env['PCHPDBFLAGS'] = '' + else: + # Default if we can't determine which version of MSVC we're using + env['PCHPDBFLAGS'] = SCons.Util.CLVar(['${(PDB and "/Yd") or ""}']) + + +def pch_emitter(target, source, env): + """Adds the object file target.""" + + validate_vars(env) + + pch = None + obj = None + + for t in target: + if SCons.Util.splitext(str(t))[1] == '.pch': + pch = t + if SCons.Util.splitext(str(t))[1] == '.obj': + obj = t + + if not obj: + obj = SCons.Util.splitext(str(pch))[0]+'.obj' + + target = [pch, obj] # pch must be first, and obj second for the PCHCOM to work + + return (target, source) + +def object_emitter(target, source, env, parent_emitter): + """Sets up the PCH dependencies for an object file.""" + + validate_vars(env) + + parent_emitter(target, source, env) + + # Add a dependency, but only if the target (e.g. 'Source1.obj') + # doesn't correspond to the pre-compiled header ('Source1.pch'). + # If the basenames match, then this was most likely caused by + # someone adding the source file to both the env.PCH() and the + # env.Program() calls, and adding the explicit dependency would + # cause a cycle on the .pch file itself. + # + # See issue #2505 for a discussion of what to do if it turns + # out this assumption causes trouble in the wild: + # https://github.com/SCons/scons/issues/2505 + if 'PCH' in env: + pch = env['PCH'] + if str(target[0]) != SCons.Util.splitext(str(pch))[0] + '.obj': + env.Depends(target, pch) + + return (target, source) + +def static_object_emitter(target, source, env): + return object_emitter(target, source, env, + SCons.Defaults.StaticObjectEmitter) + +def shared_object_emitter(target, source, env): + return object_emitter(target, source, env, + SCons.Defaults.SharedObjectEmitter) + +pch_action = SCons.Action.Action('$PCHCOM', '$PCHCOMSTR') +pch_builder = SCons.Builder.Builder(action=pch_action, suffix='.pch', + emitter=pch_emitter, + source_scanner=SCons.Tool.SourceFileScanner) + + +# Logic to build .rc files into .res files (resource files) +res_scanner = SCons.Scanner.RC.RCScan() +res_action = SCons.Action.Action('$RCCOM', '$RCCOMSTR') +res_builder = SCons.Builder.Builder(action=res_action, + src_suffix='.rc', + suffix='.res', + src_builder=[], + source_scanner=res_scanner) + +def msvc_batch_key(action, env, target, source): + """ + Returns a key to identify unique batches of sources for compilation. + + If batching is enabled (via the $MSVC_BATCH setting), then all + target+source pairs that use the same action, defined by the same + environment, and have the same target and source directories, will + be batched. + + Returning None specifies that the specified target+source should not + be batched with other compilations. + """ + + # Fixing MSVC_BATCH mode. Previous if did not work when MSVC_BATCH + # was set to False. This new version should work better. + # Note we need to do the env.subst so $MSVC_BATCH can be a reference to + # another construction variable, which is why we test for False and 0 + # as strings. + if not 'MSVC_BATCH' in env or env.subst('$MSVC_BATCH') in ('0', 'False', '', None): + # We're not using batching; return no key. + return None + t = target[0] + s = source[0] + if os.path.splitext(t.name)[0] != os.path.splitext(s.name)[0]: + # The base names are different, so this *must* be compiled + # separately; return no key. + return None + return (id(action), id(env), t.dir, s.dir) + +def msvc_output_flag(target, source, env, for_signature): + """ + Returns the correct /Fo flag for batching. + + If batching is disabled or there's only one source file, then we + return an /Fo string that specifies the target explicitly. Otherwise, + we return an /Fo string that just specifies the first target's + directory (where the Visual C/C++ compiler will put the .obj files). + """ + + # Fixing MSVC_BATCH mode. Previous if did not work when MSVC_BATCH + # was set to False. This new version should work better. Removed + # len(source)==1 as batch mode can compile only one file + # (and it also fixed problem with compiling only one changed file + # with batch mode enabled) + if not 'MSVC_BATCH' in env or env.subst('$MSVC_BATCH') in ('0', 'False', '', None): + return '/Fo$TARGET' + else: + # The Visual C/C++ compiler requires a \ at the end of the /Fo + # option to indicate an output directory. We use os.sep here so + # that the test(s) for this can be run on non-Windows systems + # without having a hard-coded backslash mess up command-line + # argument parsing. + # Adding double os.sep's as if the TARGET.dir has a space or otherwise + # needs to be quoted they are needed per MSVC's odd behavior + # See: https://github.com/SCons/scons/issues/3106 + return '/Fo${TARGET.dir}' + os.sep*2 + +CAction = SCons.Action.Action("$CCCOM", "$CCCOMSTR", + batch_key=msvc_batch_key, + targets='$CHANGED_TARGETS') +ShCAction = SCons.Action.Action("$SHCCCOM", "$SHCCCOMSTR", + batch_key=msvc_batch_key, + targets='$CHANGED_TARGETS') +CXXAction = SCons.Action.Action("$CXXCOM", "$CXXCOMSTR", + batch_key=msvc_batch_key, + targets='$CHANGED_TARGETS') +ShCXXAction = SCons.Action.Action("$SHCXXCOM", "$SHCXXCOMSTR", + batch_key=msvc_batch_key, + targets='$CHANGED_TARGETS') + +def generate(env): + """Add Builders and construction variables for MSVC++ to an Environment.""" + static_obj, shared_obj = SCons.Tool.createObjBuilders(env) + + # TODO(batch): shouldn't reach in to cmdgen this way; necessary + # for now to bypass the checks in Builder.DictCmdGenerator.__call__() + # and allow .cc and .cpp to be compiled in the same command line. + static_obj.cmdgen.source_ext_match = False + shared_obj.cmdgen.source_ext_match = False + + for suffix in CSuffixes: + static_obj.add_action(suffix, CAction) + shared_obj.add_action(suffix, ShCAction) + static_obj.add_emitter(suffix, static_object_emitter) + shared_obj.add_emitter(suffix, shared_object_emitter) + + for suffix in CXXSuffixes: + static_obj.add_action(suffix, CXXAction) + shared_obj.add_action(suffix, ShCXXAction) + static_obj.add_emitter(suffix, static_object_emitter) + shared_obj.add_emitter(suffix, shared_object_emitter) + + env['CCPDBFLAGS'] = SCons.Util.CLVar(['${(PDB and "/Z7") or ""}']) + env['CCPCHFLAGS'] = SCons.Util.CLVar(['${(PCH and "/Yu%s \\\"/Fp%s\\\""%(PCHSTOP or "",File(PCH))) or ""}']) + env['_MSVC_OUTPUT_FLAG'] = msvc_output_flag + env['_CCCOMCOM'] = '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS $CCPCHFLAGS $CCPDBFLAGS' + env['CC'] = 'cl' + env['CCFLAGS'] = SCons.Util.CLVar('/nologo') + env['CFLAGS'] = SCons.Util.CLVar('') + env['CCCOM'] = '${TEMPFILE("$CC $_MSVC_OUTPUT_FLAG /c $CHANGED_SOURCES $CFLAGS $CCFLAGS $_CCCOMCOM","$CCCOMSTR")}' + env['SHCC'] = '$CC' + env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS') + env['SHCFLAGS'] = SCons.Util.CLVar('$CFLAGS') + env['SHCCCOM'] = '${TEMPFILE("$SHCC $_MSVC_OUTPUT_FLAG /c $CHANGED_SOURCES $SHCFLAGS $SHCCFLAGS $_CCCOMCOM","$SHCCCOMSTR")}' + env['CXX'] = '$CC' + env['CXXFLAGS'] = SCons.Util.CLVar('$( /TP $)') + env['CXXCOM'] = '${TEMPFILE("$CXX $_MSVC_OUTPUT_FLAG /c $CHANGED_SOURCES $CXXFLAGS $CCFLAGS $_CCCOMCOM","$CXXCOMSTR")}' + env['SHCXX'] = '$CXX' + env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS') + env['SHCXXCOM'] = '${TEMPFILE("$SHCXX $_MSVC_OUTPUT_FLAG /c $CHANGED_SOURCES $SHCXXFLAGS $SHCCFLAGS $_CCCOMCOM","$SHCXXCOMSTR")}' + env['CPPDEFPREFIX'] = '/D' + env['CPPDEFSUFFIX'] = '' + env['INCPREFIX'] = '/I' + env['INCSUFFIX'] = '' +# env.Append(OBJEMITTER = [static_object_emitter]) +# env.Append(SHOBJEMITTER = [shared_object_emitter]) + env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1 + + env['RC'] = 'rc' + env['RCFLAGS'] = SCons.Util.CLVar('/nologo') + env['RCSUFFIXES']=['.rc','.rc2'] + env['RCCOM'] = '$RC $_CPPDEFFLAGS $_CPPINCFLAGS $RCFLAGS /fo$TARGET $SOURCES' + env['BUILDERS']['RES'] = res_builder + env['OBJPREFIX'] = '' + env['OBJSUFFIX'] = '.obj' + env['SHOBJPREFIX'] = '$OBJPREFIX' + env['SHOBJSUFFIX'] = '$OBJSUFFIX' + + # MSVC probably wont support unistd.h so default + # without it for lex generation + env["LEXUNISTD"] = SCons.Util.CLVar("--nounistd") + + # Set-up ms tools paths + msvc_setup_env_once(env) + + env['CFILESUFFIX'] = '.c' + env['CXXFILESUFFIX'] = '.cc' + + msvc_set_PCHPDBFLAGS(env) + + + env['PCHCOM'] = '$CXX /Fo${TARGETS[1]} $CXXFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Yc$PCHSTOP /Fp${TARGETS[0]} $CCPDBFLAGS $PCHPDBFLAGS' + env['BUILDERS']['PCH'] = pch_builder + + if 'ENV' not in env: + env['ENV'] = {} + if 'SystemRoot' not in env['ENV']: # required for dlls in the winsxs folders + env['ENV']['SystemRoot'] = SCons.Platform.win32.get_system_root() + +def exists(env): + return msvc_exists(env) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/msvs.py b/tools/scons/scons-local-3.0.5/SCons/Tool/msvs.py new file mode 100755 index 0000000000..afe4bef326 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/msvs.py @@ -0,0 +1,2009 @@ +"""SCons.Tool.msvs + +Tool-specific initialization for Microsoft Visual Studio project files. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +from __future__ import print_function + +__revision__ = "src/engine/SCons/Tool/msvs.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.compat + +import base64 +import hashlib +import ntpath +import os +import pickle +import re +import sys + +import SCons.Builder +import SCons.Node.FS +import SCons.Platform.win32 +import SCons.Script.SConscript +import SCons.PathList +import SCons.Util +import SCons.Warnings + +from .MSCommon import msvc_exists, msvc_setup_env_once +from SCons.Defaults import processDefines +from SCons.compat import PICKLE_PROTOCOL + +############################################################################## +# Below here are the classes and functions for generation of +# DSP/DSW/SLN/VCPROJ files. +############################################################################## + +def xmlify(s): + s = s.replace("&", "&") # do this first + s = s.replace("'", "'") + s = s.replace('"', """) + s = s.replace('<', "<") + s = s.replace('>', ">") + s = s.replace('\n', ' ') + return s + +# Process a CPPPATH list in includes, given the env, target and source. +# Returns a tuple of nodes. +def processIncludes(includes, env, target, source): + return SCons.PathList.PathList(includes).subst_path(env, target, source) + + +external_makefile_guid = '{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}' + +def _generateGUID(slnfile, name): + """This generates a dummy GUID for the sln file to use. It is + based on the MD5 signatures of the sln filename plus the name of + the project. It basically just needs to be unique, and not + change with each invocation.""" + m = hashlib.md5() + # Normalize the slnfile path to a Windows path (\ separators) so + # the generated file has a consistent GUID even if we generate + # it on a non-Windows platform. + m.update(bytearray(ntpath.normpath(str(slnfile)) + str(name),'utf-8')) + solution = m.hexdigest().upper() + # convert most of the signature to GUID form (discard the rest) + solution = "{" + solution[:8] + "-" + solution[8:12] + "-" + solution[12:16] + "-" + solution[16:20] + "-" + solution[20:32] + "}" + return solution + +version_re = re.compile(r'(\d+\.\d+)(.*)') + +def msvs_parse_version(s): + """ + Split a Visual Studio version, which may in fact be something like + '7.0Exp', into is version number (returned as a float) and trailing + "suite" portion. + """ + num, suite = version_re.match(s).groups() + return float(num), suite + +# This is how we re-invoke SCons from inside MSVS Project files. +# The problem is that we might have been invoked as either scons.bat +# or scons.py. If we were invoked directly as scons.py, then we could +# use sys.argv[0] to find the SCons "executable," but that doesn't work +# if we were invoked as scons.bat, which uses "python -c" to execute +# things and ends up with "-c" as sys.argv[0]. Consequently, we have +# the MSVS Project file invoke SCons the same way that scons.bat does, +# which works regardless of how we were invoked. +def getExecScriptMain(env, xml=None): + scons_home = env.get('SCONS_HOME') + if not scons_home and 'SCONS_LIB_DIR' in os.environ: + scons_home = os.environ['SCONS_LIB_DIR'] + if scons_home: + exec_script_main = "from os.path import join; import sys; sys.path = [ r'%s' ] + sys.path; import SCons.Script; SCons.Script.main()" % scons_home + else: + version = SCons.__version__ + exec_script_main = "from os.path import join; import sys; sys.path = [ join(sys.prefix, 'Lib', 'site-packages', 'scons-%(version)s'), join(sys.prefix, 'scons-%(version)s'), join(sys.prefix, 'Lib', 'site-packages', 'scons'), join(sys.prefix, 'scons') ] + sys.path; import SCons.Script; SCons.Script.main()" % locals() + if xml: + exec_script_main = xmlify(exec_script_main) + return exec_script_main + +# The string for the Python executable we tell the Project file to use +# is either sys.executable or, if an external PYTHON_ROOT environment +# variable exists, $(PYTHON)ROOT\\python.exe (generalized a little to +# pluck the actual executable name from sys.executable). +try: + python_root = os.environ['PYTHON_ROOT'] +except KeyError: + python_executable = sys.executable +else: + python_executable = os.path.join('$$(PYTHON_ROOT)', + os.path.split(sys.executable)[1]) + +class Config(object): + pass + +def splitFully(path): + dir, base = os.path.split(path) + if dir and dir != '' and dir != path: + return splitFully(dir)+[base] + if base == '': + return [] + return [base] + +def makeHierarchy(sources): + """Break a list of files into a hierarchy; for each value, if it is a string, + then it is a file. If it is a dictionary, it is a folder. The string is + the original path of the file.""" + + hierarchy = {} + for file in sources: + path = splitFully(file) + if len(path): + dict = hierarchy + for part in path[:-1]: + if part not in dict: + dict[part] = {} + dict = dict[part] + dict[path[-1]] = file + #else: + # print 'Warning: failed to decompose path for '+str(file) + return hierarchy + +class _UserGenerator(object): + ''' + Base class for .dsp.user file generator + ''' + # Default instance values. + # Ok ... a bit defensive, but it does not seem reasonable to crash the + # build for a workspace user file. :-) + usrhead = None + usrdebg = None + usrconf = None + createfile = False + def __init__(self, dspfile, source, env): + # DebugSettings should be a list of debug dictionary sorted in the same order + # as the target list and variants + if 'variant' not in env: + raise SCons.Errors.InternalError("You must specify a 'variant' argument (i.e. 'Debug' or " +\ + "'Release') to create an MSVSProject.") + elif SCons.Util.is_String(env['variant']): + variants = [env['variant']] + elif SCons.Util.is_List(env['variant']): + variants = env['variant'] + + if 'DebugSettings' not in env or env['DebugSettings'] is None: + dbg_settings = [] + elif SCons.Util.is_Dict(env['DebugSettings']): + dbg_settings = [env['DebugSettings']] + elif SCons.Util.is_List(env['DebugSettings']): + if len(env['DebugSettings']) != len(variants): + raise SCons.Errors.InternalError("Sizes of 'DebugSettings' and 'variant' lists must be the same.") + dbg_settings = [] + for ds in env['DebugSettings']: + if SCons.Util.is_Dict(ds): + dbg_settings.append(ds) + else: + dbg_settings.append({}) + else: + dbg_settings = [] + + if len(dbg_settings) == 1: + dbg_settings = dbg_settings * len(variants) + + self.createfile = self.usrhead and self.usrdebg and self.usrconf and \ + dbg_settings and bool([ds for ds in dbg_settings if ds]) + + if self.createfile: + dbg_settings = dict(list(zip(variants, dbg_settings))) + for var, src in dbg_settings.items(): + # Update only expected keys + trg = {} + for key in [k for k in list(self.usrdebg.keys()) if k in src]: + trg[key] = str(src[key]) + self.configs[var].debug = trg + + def UserHeader(self): + encoding = self.env.subst('$MSVSENCODING') + versionstr = self.versionstr + self.usrfile.write(self.usrhead % locals()) + + def UserProject(self): + pass + + def Build(self): + if not self.createfile: + return + try: + filename = self.dspabs +'.user' + self.usrfile = open(filename, 'w') + except IOError as detail: + raise SCons.Errors.InternalError('Unable to open "' + filename + '" for writing:' + str(detail)) + else: + self.UserHeader() + self.UserProject() + self.usrfile.close() + +V9UserHeader = """\ + + +\t +""" + +V9UserConfiguration = """\ +\t\t +\t\t\t +\t\t +""" + +V9DebugSettings = { +'Command':'$(TargetPath)', +'WorkingDirectory': None, +'CommandArguments': None, +'Attach':'false', +'DebuggerType':'3', +'Remote':'1', +'RemoteMachine': None, +'RemoteCommand': None, +'HttpUrl': None, +'PDBPath': None, +'SQLDebugging': None, +'Environment': None, +'EnvironmentMerge':'true', +'DebuggerFlavor': None, +'MPIRunCommand': None, +'MPIRunArguments': None, +'MPIRunWorkingDirectory': None, +'ApplicationCommand': None, +'ApplicationArguments': None, +'ShimCommand': None, +'MPIAcceptMode': None, +'MPIAcceptFilter': None, +} + +class _GenerateV7User(_UserGenerator): + """Generates a Project file for MSVS .NET""" + def __init__(self, dspfile, source, env): + if self.version_num >= 9.0: + self.usrhead = V9UserHeader + self.usrconf = V9UserConfiguration + self.usrdebg = V9DebugSettings + _UserGenerator.__init__(self, dspfile, source, env) + + def UserProject(self): + confkeys = sorted(self.configs.keys()) + for kind in confkeys: + variant = self.configs[kind].variant + platform = self.configs[kind].platform + debug = self.configs[kind].debug + if debug: + debug_settings = '\n'.join(['\t\t\t\t%s="%s"' % (key, xmlify(value)) + for key, value in debug.items() + if value is not None]) + self.usrfile.write(self.usrconf % locals()) + self.usrfile.write('\t\n') + +V10UserHeader = """\ + + +""" + +V10UserConfiguration = """\ +\t +%(debug_settings)s +\t +""" + +V10DebugSettings = { +'LocalDebuggerCommand': None, +'LocalDebuggerCommandArguments': None, +'LocalDebuggerEnvironment': None, +'DebuggerFlavor': 'WindowsLocalDebugger', +'LocalDebuggerWorkingDirectory': None, +'LocalDebuggerAttach': None, +'LocalDebuggerDebuggerType': None, +'LocalDebuggerMergeEnvironment': None, +'LocalDebuggerSQLDebugging': None, +'RemoteDebuggerCommand': None, +'RemoteDebuggerCommandArguments': None, +'RemoteDebuggerWorkingDirectory': None, +'RemoteDebuggerServerName': None, +'RemoteDebuggerConnection': None, +'RemoteDebuggerDebuggerType': None, +'RemoteDebuggerAttach': None, +'RemoteDebuggerSQLDebugging': None, +'DeploymentDirectory': None, +'AdditionalFiles': None, +'RemoteDebuggerDeployDebugCppRuntime': None, +'WebBrowserDebuggerHttpUrl': None, +'WebBrowserDebuggerDebuggerType': None, +'WebServiceDebuggerHttpUrl': None, +'WebServiceDebuggerDebuggerType': None, +'WebServiceDebuggerSQLDebugging': None, +} + +class _GenerateV10User(_UserGenerator): + """Generates a Project'user file for MSVS 2010""" + + def __init__(self, dspfile, source, env): + self.versionstr = '4.0' + self.usrhead = V10UserHeader + self.usrconf = V10UserConfiguration + self.usrdebg = V10DebugSettings + _UserGenerator.__init__(self, dspfile, source, env) + + def UserProject(self): + confkeys = sorted(self.configs.keys()) + for kind in confkeys: + variant = self.configs[kind].variant + platform = self.configs[kind].platform + debug = self.configs[kind].debug + if debug: + debug_settings = '\n'.join(['\t\t<%s>%s' % (key, xmlify(value), key) + for key, value in debug.items() + if value is not None]) + self.usrfile.write(self.usrconf % locals()) + self.usrfile.write('') + +class _DSPGenerator(object): + """ Base class for DSP generators """ + + srcargs = [ + 'srcs', + 'incs', + 'localincs', + 'resources', + 'misc'] + + def __init__(self, dspfile, source, env): + self.dspfile = str(dspfile) + try: + get_abspath = dspfile.get_abspath + except AttributeError: + self.dspabs = os.path.abspath(dspfile) + else: + self.dspabs = get_abspath() + + if 'variant' not in env: + raise SCons.Errors.InternalError("You must specify a 'variant' argument (i.e. 'Debug' or " +\ + "'Release') to create an MSVSProject.") + elif SCons.Util.is_String(env['variant']): + variants = [env['variant']] + elif SCons.Util.is_List(env['variant']): + variants = env['variant'] + + if 'buildtarget' not in env or env['buildtarget'] == None: + buildtarget = [''] + elif SCons.Util.is_String(env['buildtarget']): + buildtarget = [env['buildtarget']] + elif SCons.Util.is_List(env['buildtarget']): + if len(env['buildtarget']) != len(variants): + raise SCons.Errors.InternalError("Sizes of 'buildtarget' and 'variant' lists must be the same.") + buildtarget = [] + for bt in env['buildtarget']: + if SCons.Util.is_String(bt): + buildtarget.append(bt) + else: + buildtarget.append(bt.get_abspath()) + else: + buildtarget = [env['buildtarget'].get_abspath()] + if len(buildtarget) == 1: + bt = buildtarget[0] + buildtarget = [] + for _ in variants: + buildtarget.append(bt) + + if 'outdir' not in env or env['outdir'] == None: + outdir = [''] + elif SCons.Util.is_String(env['outdir']): + outdir = [env['outdir']] + elif SCons.Util.is_List(env['outdir']): + if len(env['outdir']) != len(variants): + raise SCons.Errors.InternalError("Sizes of 'outdir' and 'variant' lists must be the same.") + outdir = [] + for s in env['outdir']: + if SCons.Util.is_String(s): + outdir.append(s) + else: + outdir.append(s.get_abspath()) + else: + outdir = [env['outdir'].get_abspath()] + if len(outdir) == 1: + s = outdir[0] + outdir = [] + for v in variants: + outdir.append(s) + + if 'runfile' not in env or env['runfile'] == None: + runfile = buildtarget[-1:] + elif SCons.Util.is_String(env['runfile']): + runfile = [env['runfile']] + elif SCons.Util.is_List(env['runfile']): + if len(env['runfile']) != len(variants): + raise SCons.Errors.InternalError("Sizes of 'runfile' and 'variant' lists must be the same.") + runfile = [] + for s in env['runfile']: + if SCons.Util.is_String(s): + runfile.append(s) + else: + runfile.append(s.get_abspath()) + else: + runfile = [env['runfile'].get_abspath()] + if len(runfile) == 1: + s = runfile[0] + runfile = [] + for v in variants: + runfile.append(s) + + self.sconscript = env['MSVSSCONSCRIPT'] + + if 'cmdargs' not in env or env['cmdargs'] == None: + cmdargs = [''] * len(variants) + elif SCons.Util.is_String(env['cmdargs']): + cmdargs = [env['cmdargs']] * len(variants) + elif SCons.Util.is_List(env['cmdargs']): + if len(env['cmdargs']) != len(variants): + raise SCons.Errors.InternalError("Sizes of 'cmdargs' and 'variant' lists must be the same.") + else: + cmdargs = env['cmdargs'] + + self.env = env + + if 'name' in self.env: + self.name = self.env['name'] + else: + self.name = os.path.basename(SCons.Util.splitext(self.dspfile)[0]) + self.name = self.env.subst(self.name) + + sourcenames = [ + 'Source Files', + 'Header Files', + 'Local Headers', + 'Resource Files', + 'Other Files'] + + self.sources = {} + for n in sourcenames: + self.sources[n] = [] + + self.configs = {} + + self.nokeep = 0 + if 'nokeep' in env and env['variant'] != 0: + self.nokeep = 1 + + if self.nokeep == 0 and os.path.exists(self.dspabs): + self.Parse() + + for t in zip(sourcenames,self.srcargs): + if t[1] in self.env: + if SCons.Util.is_List(self.env[t[1]]): + for i in self.env[t[1]]: + if not i in self.sources[t[0]]: + self.sources[t[0]].append(i) + else: + if not self.env[t[1]] in self.sources[t[0]]: + self.sources[t[0]].append(self.env[t[1]]) + + for n in sourcenames: + self.sources[n].sort(key=lambda a: a.lower()) + + def AddConfig(self, variant, buildtarget, outdir, runfile, cmdargs, dspfile=dspfile): + config = Config() + config.buildtarget = buildtarget + config.outdir = outdir + config.cmdargs = cmdargs + config.runfile = runfile + + match = re.match(r'(.*)\|(.*)', variant) + if match: + config.variant = match.group(1) + config.platform = match.group(2) + else: + config.variant = variant + config.platform = 'Win32' + + self.configs[variant] = config + print("Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dspfile) + "'") + + for i in range(len(variants)): + AddConfig(self, variants[i], buildtarget[i], outdir[i], runfile[i], cmdargs[i]) + + self.platforms = [] + for key in list(self.configs.keys()): + platform = self.configs[key].platform + if not platform in self.platforms: + self.platforms.append(platform) + + def Build(self): + pass + +V6DSPHeader = """\ +# Microsoft Developer Studio Project File - Name="%(name)s" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) External Target" 0x0106 + +CFG=%(name)s - Win32 %(confkey)s +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "%(name)s.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "%(name)s.mak" CFG="%(name)s - Win32 %(confkey)s" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +""" + +class _GenerateV6DSP(_DSPGenerator): + """Generates a Project file for MSVS 6.0""" + + def PrintHeader(self): + # pick a default config + confkeys = sorted(self.configs.keys()) + + name = self.name + confkey = confkeys[0] + + self.file.write(V6DSPHeader % locals()) + + for kind in confkeys: + self.file.write('!MESSAGE "%s - Win32 %s" (based on "Win32 (x86) External Target")\n' % (name, kind)) + + self.file.write('!MESSAGE \n\n') + + def PrintProject(self): + name = self.name + self.file.write('# Begin Project\n' + '# PROP AllowPerConfigDependencies 0\n' + '# PROP Scc_ProjName ""\n' + '# PROP Scc_LocalPath ""\n\n') + + first = 1 + confkeys = sorted(self.configs.keys()) + for kind in confkeys: + outdir = self.configs[kind].outdir + buildtarget = self.configs[kind].buildtarget + if first == 1: + self.file.write('!IF "$(CFG)" == "%s - Win32 %s"\n\n' % (name, kind)) + first = 0 + else: + self.file.write('\n!ELSEIF "$(CFG)" == "%s - Win32 %s"\n\n' % (name, kind)) + + env_has_buildtarget = 'MSVSBUILDTARGET' in self.env + if not env_has_buildtarget: + self.env['MSVSBUILDTARGET'] = buildtarget + + # have to write this twice, once with the BASE settings, and once without + for base in ("BASE ",""): + self.file.write('# PROP %sUse_MFC 0\n' + '# PROP %sUse_Debug_Libraries ' % (base, base)) + if kind.lower().find('debug') < 0: + self.file.write('0\n') + else: + self.file.write('1\n') + self.file.write('# PROP %sOutput_Dir "%s"\n' + '# PROP %sIntermediate_Dir "%s"\n' % (base,outdir,base,outdir)) + cmd = 'echo Starting SCons && ' + self.env.subst('$MSVSBUILDCOM', 1) + self.file.write('# PROP %sCmd_Line "%s"\n' + '# PROP %sRebuild_Opt "-c && %s"\n' + '# PROP %sTarget_File "%s"\n' + '# PROP %sBsc_Name ""\n' + '# PROP %sTarget_Dir ""\n'\ + %(base,cmd,base,cmd,base,buildtarget,base,base)) + + if not env_has_buildtarget: + del self.env['MSVSBUILDTARGET'] + + self.file.write('\n!ENDIF\n\n' + '# Begin Target\n\n') + for kind in confkeys: + self.file.write('# Name "%s - Win32 %s"\n' % (name,kind)) + self.file.write('\n') + first = 0 + for kind in confkeys: + if first == 0: + self.file.write('!IF "$(CFG)" == "%s - Win32 %s"\n\n' % (name,kind)) + first = 1 + else: + self.file.write('!ELSEIF "$(CFG)" == "%s - Win32 %s"\n\n' % (name,kind)) + self.file.write('!ENDIF \n\n') + self.PrintSourceFiles() + self.file.write('# End Target\n' + '# End Project\n') + + if self.nokeep == 0: + # now we pickle some data and add it to the file -- MSDEV will ignore it. + pdata = pickle.dumps(self.configs,PICKLE_PROTOCOL) + pdata = base64.encodestring(pdata).decode() + self.file.write(pdata + '\n') + pdata = pickle.dumps(self.sources,PICKLE_PROTOCOL) + pdata = base64.encodestring(pdata).decode() + self.file.write(pdata + '\n') + + def PrintSourceFiles(self): + categories = {'Source Files': 'cpp|c|cxx|l|y|def|odl|idl|hpj|bat', + 'Header Files': 'h|hpp|hxx|hm|inl', + 'Local Headers': 'h|hpp|hxx|hm|inl', + 'Resource Files': 'r|rc|ico|cur|bmp|dlg|rc2|rct|bin|cnt|rtf|gif|jpg|jpeg|jpe', + 'Other Files': ''} + + for kind in sorted(list(categories.keys()), key=lambda a: a.lower()): + if not self.sources[kind]: + continue # skip empty groups + + self.file.write('# Begin Group "' + kind + '"\n\n') + typelist = categories[kind].replace('|', ';') + self.file.write('# PROP Default_Filter "' + typelist + '"\n') + + for file in self.sources[kind]: + file = os.path.normpath(file) + self.file.write('# Begin Source File\n\n' + 'SOURCE="' + file + '"\n' + '# End Source File\n') + self.file.write('# End Group\n') + + # add the SConscript file outside of the groups + self.file.write('# Begin Source File\n\n' + 'SOURCE="' + str(self.sconscript) + '"\n' + '# End Source File\n') + + def Parse(self): + try: + dspfile = open(self.dspabs,'r') + except IOError: + return # doesn't exist yet, so can't add anything to configs. + + line = dspfile.readline() + while line: + if line.find("# End Project") > -1: + break + line = dspfile.readline() + + line = dspfile.readline() + datas = line + while line and line != '\n': + line = dspfile.readline() + datas = datas + line + + # OK, we've found our little pickled cache of data. + try: + datas = base64.decodestring(datas) + data = pickle.loads(datas) + except KeyboardInterrupt: + raise + except: + return # unable to unpickle any data for some reason + + self.configs.update(data) + + data = None + line = dspfile.readline() + datas = line + while line and line != '\n': + line = dspfile.readline() + datas = datas + line + + # OK, we've found our little pickled cache of data. + # it has a "# " in front of it, so we strip that. + try: + datas = base64.decodestring(datas) + data = pickle.loads(datas) + except KeyboardInterrupt: + raise + except: + return # unable to unpickle any data for some reason + + self.sources.update(data) + + def Build(self): + try: + self.file = open(self.dspabs,'w') + except IOError as detail: + raise SCons.Errors.InternalError('Unable to open "' + self.dspabs + '" for writing:' + str(detail)) + else: + self.PrintHeader() + self.PrintProject() + self.file.close() + +V7DSPHeader = """\ + + +""" + +V7DSPConfiguration = """\ +\t\t +\t\t\t +\t\t +""" + +V8DSPHeader = """\ + + +""" + +V8DSPConfiguration = """\ +\t\t +\t\t\t +\t\t +""" +class _GenerateV7DSP(_DSPGenerator, _GenerateV7User): + """Generates a Project file for MSVS .NET""" + + def __init__(self, dspfile, source, env): + _DSPGenerator.__init__(self, dspfile, source, env) + self.version = env['MSVS_VERSION'] + self.version_num, self.suite = msvs_parse_version(self.version) + if self.version_num >= 9.0: + self.versionstr = '9.00' + self.dspheader = V8DSPHeader + self.dspconfiguration = V8DSPConfiguration + elif self.version_num >= 8.0: + self.versionstr = '8.00' + self.dspheader = V8DSPHeader + self.dspconfiguration = V8DSPConfiguration + else: + if self.version_num >= 7.1: + self.versionstr = '7.10' + else: + self.versionstr = '7.00' + self.dspheader = V7DSPHeader + self.dspconfiguration = V7DSPConfiguration + self.file = None + + _GenerateV7User.__init__(self, dspfile, source, env) + + def PrintHeader(self): + env = self.env + versionstr = self.versionstr + name = self.name + encoding = self.env.subst('$MSVSENCODING') + scc_provider = env.get('MSVS_SCC_PROVIDER', '') + scc_project_name = env.get('MSVS_SCC_PROJECT_NAME', '') + scc_aux_path = env.get('MSVS_SCC_AUX_PATH', '') + # MSVS_SCC_LOCAL_PATH is kept for backwards compatibility purpose and should + # be deprecated as soon as possible. + scc_local_path_legacy = env.get('MSVS_SCC_LOCAL_PATH', '') + scc_connection_root = env.get('MSVS_SCC_CONNECTION_ROOT', os.curdir) + scc_local_path = os.path.relpath(scc_connection_root, os.path.dirname(self.dspabs)) + project_guid = env.get('MSVS_PROJECT_GUID', '') + if not project_guid: + project_guid = _generateGUID(self.dspfile, '') + if scc_provider != '': + scc_attrs = '\tSccProjectName="%s"\n' % scc_project_name + if scc_aux_path != '': + scc_attrs += '\tSccAuxPath="%s"\n' % scc_aux_path + scc_attrs += ('\tSccLocalPath="%s"\n' + '\tSccProvider="%s"' % (scc_local_path, scc_provider)) + elif scc_local_path_legacy != '': + # This case is kept for backwards compatibility purpose and should + # be deprecated as soon as possible. + scc_attrs = ('\tSccProjectName="%s"\n' + '\tSccLocalPath="%s"' % (scc_project_name, scc_local_path_legacy)) + else: + self.dspheader = self.dspheader.replace('%(scc_attrs)s\n', '') + + self.file.write(self.dspheader % locals()) + + self.file.write('\t\n') + for platform in self.platforms: + self.file.write( + '\t\t\n' % platform) + self.file.write('\t\n') + + if self.version_num >= 8.0: + self.file.write('\t\n' + '\t\n') + + def PrintProject(self): + self.file.write('\t\n') + + confkeys = sorted(self.configs.keys()) + for kind in confkeys: + variant = self.configs[kind].variant + platform = self.configs[kind].platform + outdir = self.configs[kind].outdir + buildtarget = self.configs[kind].buildtarget + runfile = self.configs[kind].runfile + cmdargs = self.configs[kind].cmdargs + + env_has_buildtarget = 'MSVSBUILDTARGET' in self.env + if not env_has_buildtarget: + self.env['MSVSBUILDTARGET'] = buildtarget + + starting = 'echo Starting SCons && ' + if cmdargs: + cmdargs = ' ' + cmdargs + else: + cmdargs = '' + buildcmd = xmlify(starting + self.env.subst('$MSVSBUILDCOM', 1) + cmdargs) + rebuildcmd = xmlify(starting + self.env.subst('$MSVSREBUILDCOM', 1) + cmdargs) + cleancmd = xmlify(starting + self.env.subst('$MSVSCLEANCOM', 1) + cmdargs) + + # This isn't perfect; CPPDEFINES and CPPPATH can contain $TARGET and $SOURCE, + # so they could vary depending on the command being generated. This code + # assumes they don't. + preprocdefs = xmlify(';'.join(processDefines(self.env.get('CPPDEFINES', [])))) + includepath_Dirs = processIncludes(self.env.get('CPPPATH', []), self.env, None, None) + includepath = xmlify(';'.join([str(x) for x in includepath_Dirs])) + + if not env_has_buildtarget: + del self.env['MSVSBUILDTARGET'] + + self.file.write(self.dspconfiguration % locals()) + + self.file.write('\t\n') + + if self.version_num >= 7.1: + self.file.write('\t\n' + '\t\n') + + self.PrintSourceFiles() + + self.file.write('\n') + + if self.nokeep == 0: + # now we pickle some data and add it to the file -- MSDEV will ignore it. + pdata = pickle.dumps(self.configs,PICKLE_PROTOCOL) + pdata = base64.encodestring(pdata).decode() + self.file.write('\n') + + def printSources(self, hierarchy, commonprefix): + sorteditems = sorted(hierarchy.items(), key=lambda a: a[0].lower()) + + # First folders, then files + for key, value in sorteditems: + if SCons.Util.is_Dict(value): + self.file.write('\t\t\t\n' % (key)) + self.printSources(value, commonprefix) + self.file.write('\t\t\t\n') + + for key, value in sorteditems: + if SCons.Util.is_String(value): + file = value + if commonprefix: + file = os.path.join(commonprefix, value) + file = os.path.normpath(file) + self.file.write('\t\t\t\n' + '\t\t\t\n' % (file)) + + def PrintSourceFiles(self): + categories = {'Source Files': 'cpp;c;cxx;l;y;def;odl;idl;hpj;bat', + 'Header Files': 'h;hpp;hxx;hm;inl', + 'Local Headers': 'h;hpp;hxx;hm;inl', + 'Resource Files': 'r;rc;ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe', + 'Other Files': ''} + + self.file.write('\t\n') + + cats = sorted([k for k in list(categories.keys()) if self.sources[k]], + key=lambda a: a.lower()) + for kind in cats: + if len(cats) > 1: + self.file.write('\t\t\n' % (kind, categories[kind])) + + sources = self.sources[kind] + + # First remove any common prefix + commonprefix = None + s = list(map(os.path.normpath, sources)) + # take the dirname because the prefix may include parts + # of the filenames (e.g. if you have 'dir\abcd' and + # 'dir\acde' then the cp will be 'dir\a' ) + cp = os.path.dirname( os.path.commonprefix(s) ) + if cp and s[0][len(cp)] == os.sep: + # +1 because the filename starts after the separator + sources = [s[len(cp)+1:] for s in sources] + commonprefix = cp + + hierarchy = makeHierarchy(sources) + self.printSources(hierarchy, commonprefix=commonprefix) + + if len(cats)>1: + self.file.write('\t\t\n') + + # add the SConscript file outside of the groups + self.file.write('\t\t\n' + '\t\t\n' % str(self.sconscript)) + + self.file.write('\t\n' + '\t\n' + '\t\n') + + def Parse(self): + try: + dspfile = open(self.dspabs,'r') + except IOError: + return # doesn't exist yet, so can't add anything to configs. + + line = dspfile.readline() + while line: + if line.find('\n') + + def printFilters(self, hierarchy, name): + sorteditems = sorted(hierarchy.items(), key = lambda a: a[0].lower()) + + for key, value in sorteditems: + if SCons.Util.is_Dict(value): + filter_name = name + '\\' + key + self.filters_file.write('\t\t\n' + '\t\t\t%s\n' + '\t\t\n' % (filter_name, _generateGUID(self.dspabs, filter_name))) + self.printFilters(value, filter_name) + + def printSources(self, hierarchy, kind, commonprefix, filter_name): + keywords = {'Source Files': 'ClCompile', + 'Header Files': 'ClInclude', + 'Local Headers': 'ClInclude', + 'Resource Files': 'None', + 'Other Files': 'None'} + + sorteditems = sorted(hierarchy.items(), key = lambda a: a[0].lower()) + + # First folders, then files + for key, value in sorteditems: + if SCons.Util.is_Dict(value): + self.printSources(value, kind, commonprefix, filter_name + '\\' + key) + + for key, value in sorteditems: + if SCons.Util.is_String(value): + file = value + if commonprefix: + file = os.path.join(commonprefix, value) + file = os.path.normpath(file) + + self.file.write('\t\t<%s Include="%s" />\n' % (keywords[kind], file)) + self.filters_file.write('\t\t<%s Include="%s">\n' + '\t\t\t%s\n' + '\t\t\n' % (keywords[kind], file, filter_name, keywords[kind])) + + def PrintSourceFiles(self): + categories = {'Source Files': 'cpp;c;cxx;l;y;def;odl;idl;hpj;bat', + 'Header Files': 'h;hpp;hxx;hm;inl', + 'Local Headers': 'h;hpp;hxx;hm;inl', + 'Resource Files': 'r;rc;ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe', + 'Other Files': ''} + + cats = sorted([k for k in list(categories.keys()) if self.sources[k]], + key = lambda a: a.lower()) + + # print vcxproj.filters file first + self.filters_file.write('\t\n') + for kind in cats: + self.filters_file.write('\t\t\n' + '\t\t\t{7b42d31d-d53c-4868-8b92-ca2bc9fc052f}\n' + '\t\t\t%s\n' + '\t\t\n' % (kind, categories[kind])) + + # First remove any common prefix + sources = self.sources[kind] + commonprefix = None + s = list(map(os.path.normpath, sources)) + # take the dirname because the prefix may include parts + # of the filenames (e.g. if you have 'dir\abcd' and + # 'dir\acde' then the cp will be 'dir\a' ) + cp = os.path.dirname( os.path.commonprefix(s) ) + if cp and s[0][len(cp)] == os.sep: + # +1 because the filename starts after the separator + sources = [s[len(cp)+1:] for s in sources] + commonprefix = cp + + hierarchy = makeHierarchy(sources) + self.printFilters(hierarchy, kind) + + self.filters_file.write('\t\n') + + # then print files and filters + for kind in cats: + self.file.write('\t\n') + self.filters_file.write('\t\n') + + # First remove any common prefix + sources = self.sources[kind] + commonprefix = None + s = list(map(os.path.normpath, sources)) + # take the dirname because the prefix may include parts + # of the filenames (e.g. if you have 'dir\abcd' and + # 'dir\acde' then the cp will be 'dir\a' ) + cp = os.path.dirname( os.path.commonprefix(s) ) + if cp and s[0][len(cp)] == os.sep: + # +1 because the filename starts after the separator + sources = [s[len(cp)+1:] for s in sources] + commonprefix = cp + + hierarchy = makeHierarchy(sources) + self.printSources(hierarchy, kind, commonprefix, kind) + + self.file.write('\t\n') + self.filters_file.write('\t\n') + + # add the SConscript file outside of the groups + self.file.write('\t\n' + '\t\t\n' + #'\t\t\n' + '\t\n' % str(self.sconscript)) + + def Parse(self): + print("_GenerateV10DSP.Parse()") + + def Build(self): + try: + self.file = open(self.dspabs, 'w') + except IOError as detail: + raise SCons.Errors.InternalError('Unable to open "' + self.dspabs + '" for writing:' + str(detail)) + else: + self.PrintHeader() + self.PrintProject() + self.file.close() + + _GenerateV10User.Build(self) + +class _DSWGenerator(object): + """ Base class for DSW generators """ + def __init__(self, dswfile, source, env): + self.dswfile = os.path.normpath(str(dswfile)) + self.dsw_folder_path = os.path.dirname(os.path.abspath(self.dswfile)) + self.env = env + + if 'projects' not in env: + raise SCons.Errors.UserError("You must specify a 'projects' argument to create an MSVSSolution.") + projects = env['projects'] + if not SCons.Util.is_List(projects): + raise SCons.Errors.InternalError("The 'projects' argument must be a list of nodes.") + projects = SCons.Util.flatten(projects) + if len(projects) < 1: + raise SCons.Errors.UserError("You must specify at least one project to create an MSVSSolution.") + self.dspfiles = list(map(str, projects)) + + if 'name' in self.env: + self.name = self.env['name'] + else: + self.name = os.path.basename(SCons.Util.splitext(self.dswfile)[0]) + self.name = self.env.subst(self.name) + + def Build(self): + pass + +class _GenerateV7DSW(_DSWGenerator): + """Generates a Solution file for MSVS .NET""" + def __init__(self, dswfile, source, env): + _DSWGenerator.__init__(self, dswfile, source, env) + + self.file = None + self.version = self.env['MSVS_VERSION'] + self.version_num, self.suite = msvs_parse_version(self.version) + self.versionstr = '7.00' + if self.version_num >= 11.0: + self.versionstr = '12.00' + elif self.version_num >= 10.0: + self.versionstr = '11.00' + elif self.version_num >= 9.0: + self.versionstr = '10.00' + elif self.version_num >= 8.0: + self.versionstr = '9.00' + elif self.version_num >= 7.1: + self.versionstr = '8.00' + + if 'slnguid' in env and env['slnguid']: + self.slnguid = env['slnguid'] + else: + self.slnguid = _generateGUID(dswfile, self.name) + + self.configs = {} + + self.nokeep = 0 + if 'nokeep' in env and env['variant'] != 0: + self.nokeep = 1 + + if self.nokeep == 0 and os.path.exists(self.dswfile): + self.Parse() + + def AddConfig(self, variant, dswfile=dswfile): + config = Config() + + match = re.match(r'(.*)\|(.*)', variant) + if match: + config.variant = match.group(1) + config.platform = match.group(2) + else: + config.variant = variant + config.platform = 'Win32' + + self.configs[variant] = config + print("Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dswfile) + "'") + + if 'variant' not in env: + raise SCons.Errors.InternalError("You must specify a 'variant' argument (i.e. 'Debug' or " +\ + "'Release') to create an MSVS Solution File.") + elif SCons.Util.is_String(env['variant']): + AddConfig(self, env['variant']) + elif SCons.Util.is_List(env['variant']): + for variant in env['variant']: + AddConfig(self, variant) + + self.platforms = [] + for key in list(self.configs.keys()): + platform = self.configs[key].platform + if not platform in self.platforms: + self.platforms.append(platform) + + def GenerateProjectFilesInfo(self): + for dspfile in self.dspfiles: + dsp_folder_path, name = os.path.split(dspfile) + dsp_folder_path = os.path.abspath(dsp_folder_path) + dsp_relative_folder_path = os.path.relpath(dsp_folder_path, self.dsw_folder_path) + if dsp_relative_folder_path == os.curdir: + dsp_relative_file_path = name + else: + dsp_relative_file_path = os.path.join(dsp_relative_folder_path, name) + dspfile_info = {'NAME': name, + 'GUID': _generateGUID(dspfile, ''), + 'FOLDER_PATH': dsp_folder_path, + 'FILE_PATH': dspfile, + 'SLN_RELATIVE_FOLDER_PATH': dsp_relative_folder_path, + 'SLN_RELATIVE_FILE_PATH': dsp_relative_file_path} + self.dspfiles_info.append(dspfile_info) + + self.dspfiles_info = [] + GenerateProjectFilesInfo(self) + + def Parse(self): + try: + dswfile = open(self.dswfile,'r') + except IOError: + return # doesn't exist yet, so can't add anything to configs. + + line = dswfile.readline() + while line: + if line[:9] == "EndGlobal": + break + line = dswfile.readline() + + line = dswfile.readline() + datas = line + while line: + line = dswfile.readline() + datas = datas + line + + # OK, we've found our little pickled cache of data. + try: + datas = base64.decodestring(datas) + data = pickle.loads(datas) + except KeyboardInterrupt: + raise + except: + return # unable to unpickle any data for some reason + + self.configs.update(data) + + def PrintSolution(self): + """Writes a solution file""" + self.file.write('Microsoft Visual Studio Solution File, Format Version %s\n' % self.versionstr) + if self.version_num > 14.0: + self.file.write('# Visual Studio 15\n') + elif self.version_num >= 12.0: + self.file.write('# Visual Studio 14\n') + elif self.version_num >= 11.0: + self.file.write('# Visual Studio 11\n') + elif self.version_num >= 10.0: + self.file.write('# Visual Studio 2010\n') + elif self.version_num >= 9.0: + self.file.write('# Visual Studio 2008\n') + elif self.version_num >= 8.0: + self.file.write('# Visual Studio 2005\n') + + for dspinfo in self.dspfiles_info: + name = dspinfo['NAME'] + base, suffix = SCons.Util.splitext(name) + if suffix == '.vcproj': + name = base + self.file.write('Project("%s") = "%s", "%s", "%s"\n' + % (external_makefile_guid, name, dspinfo['SLN_RELATIVE_FILE_PATH'], dspinfo['GUID'])) + if 7.1 <= self.version_num < 8.0: + self.file.write('\tProjectSection(ProjectDependencies) = postProject\n' + '\tEndProjectSection\n') + self.file.write('EndProject\n') + + self.file.write('Global\n') + + env = self.env + if 'MSVS_SCC_PROVIDER' in env: + scc_number_of_projects = len(self.dspfiles) + 1 + slnguid = self.slnguid + scc_provider = env.get('MSVS_SCC_PROVIDER', '').replace(' ', r'\u0020') + scc_project_name = env.get('MSVS_SCC_PROJECT_NAME', '').replace(' ', r'\u0020') + scc_connection_root = env.get('MSVS_SCC_CONNECTION_ROOT', os.curdir) + scc_local_path = os.path.relpath(scc_connection_root, self.dsw_folder_path).replace('\\', '\\\\') + self.file.write('\tGlobalSection(SourceCodeControl) = preSolution\n' + '\t\tSccNumberOfProjects = %(scc_number_of_projects)d\n' + '\t\tSccProjectName0 = %(scc_project_name)s\n' + '\t\tSccLocalPath0 = %(scc_local_path)s\n' + '\t\tSccProvider0 = %(scc_provider)s\n' + '\t\tCanCheckoutShared = true\n' % locals()) + sln_relative_path_from_scc = os.path.relpath(self.dsw_folder_path, scc_connection_root) + if sln_relative_path_from_scc != os.curdir: + self.file.write('\t\tSccProjectFilePathRelativizedFromConnection0 = %s\\\\\n' + % sln_relative_path_from_scc.replace('\\', '\\\\')) + if self.version_num < 8.0: + # When present, SolutionUniqueID is automatically removed by VS 2005 + # TODO: check for Visual Studio versions newer than 2005 + self.file.write('\t\tSolutionUniqueID = %s\n' % slnguid) + for dspinfo in self.dspfiles_info: + i = self.dspfiles_info.index(dspinfo) + 1 + dsp_relative_file_path = dspinfo['SLN_RELATIVE_FILE_PATH'].replace('\\', '\\\\') + dsp_scc_relative_folder_path = os.path.relpath(dspinfo['FOLDER_PATH'], scc_connection_root).replace('\\', '\\\\') + self.file.write('\t\tSccProjectUniqueName%(i)s = %(dsp_relative_file_path)s\n' + '\t\tSccLocalPath%(i)d = %(scc_local_path)s\n' + '\t\tCanCheckoutShared = true\n' + '\t\tSccProjectFilePathRelativizedFromConnection%(i)s = %(dsp_scc_relative_folder_path)s\\\\\n' + % locals()) + self.file.write('\tEndGlobalSection\n') + if self.version_num >= 8.0: + self.file.write('\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n') + else: + self.file.write('\tGlobalSection(SolutionConfiguration) = preSolution\n') + + confkeys = sorted(self.configs.keys()) + cnt = 0 + for name in confkeys: + variant = self.configs[name].variant + platform = self.configs[name].platform + if self.version_num >= 8.0: + self.file.write('\t\t%s|%s = %s|%s\n' % (variant, platform, variant, platform)) + else: + self.file.write('\t\tConfigName.%d = %s\n' % (cnt, variant)) + cnt = cnt + 1 + self.file.write('\tEndGlobalSection\n') + if self.version_num <= 7.1: + self.file.write('\tGlobalSection(ProjectDependencies) = postSolution\n' + '\tEndGlobalSection\n') + if self.version_num >= 8.0: + self.file.write('\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n') + else: + self.file.write('\tGlobalSection(ProjectConfiguration) = postSolution\n') + + for name in confkeys: + variant = self.configs[name].variant + platform = self.configs[name].platform + if self.version_num >= 8.0: + for dspinfo in self.dspfiles_info: + guid = dspinfo['GUID'] + self.file.write('\t\t%s.%s|%s.ActiveCfg = %s|%s\n' + '\t\t%s.%s|%s.Build.0 = %s|%s\n' % (guid,variant,platform,variant,platform,guid,variant,platform,variant,platform)) + else: + for dspinfo in self.dspfiles_info: + guid = dspinfo['GUID'] + self.file.write('\t\t%s.%s.ActiveCfg = %s|%s\n' + '\t\t%s.%s.Build.0 = %s|%s\n' %(guid,variant,variant,platform,guid,variant,variant,platform)) + + self.file.write('\tEndGlobalSection\n') + + if self.version_num >= 8.0: + self.file.write('\tGlobalSection(SolutionProperties) = preSolution\n' + '\t\tHideSolutionNode = FALSE\n' + '\tEndGlobalSection\n') + else: + self.file.write('\tGlobalSection(ExtensibilityGlobals) = postSolution\n' + '\tEndGlobalSection\n' + '\tGlobalSection(ExtensibilityAddIns) = postSolution\n' + '\tEndGlobalSection\n') + self.file.write('EndGlobal\n') + if self.nokeep == 0: + pdata = pickle.dumps(self.configs,PICKLE_PROTOCOL) + pdata = base64.encodestring(pdata).decode() + self.file.write(pdata) + self.file.write('\n') + + def Build(self): + try: + self.file = open(self.dswfile,'w') + except IOError as detail: + raise SCons.Errors.InternalError('Unable to open "' + self.dswfile + '" for writing:' + str(detail)) + else: + self.PrintSolution() + self.file.close() + +V6DSWHeader = """\ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "%(name)s"="%(dspfile)s" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### +""" + +class _GenerateV6DSW(_DSWGenerator): + """Generates a Workspace file for MSVS 6.0""" + + def PrintWorkspace(self): + """ writes a DSW file """ + name = self.name + dspfile = os.path.relpath(self.dspfiles[0], self.dsw_folder_path) + self.file.write(V6DSWHeader % locals()) + + def Build(self): + try: + self.file = open(self.dswfile,'w') + except IOError as detail: + raise SCons.Errors.InternalError('Unable to open "' + self.dswfile + '" for writing:' + str(detail)) + else: + self.PrintWorkspace() + self.file.close() + + +def GenerateDSP(dspfile, source, env): + """Generates a Project file based on the version of MSVS that is being used""" + + version_num = 6.0 + if 'MSVS_VERSION' in env: + version_num, suite = msvs_parse_version(env['MSVS_VERSION']) + if version_num > 14.0: + g = _GenerateV10DSP(dspfile, V15DSPHeader, source, env) + g.Build() + elif version_num >= 10.0: + g = _GenerateV10DSP(dspfile, V10DSPHeader, source, env) + g.Build() + elif version_num >= 7.0: + g = _GenerateV7DSP(dspfile, source, env) + g.Build() + else: + g = _GenerateV6DSP(dspfile, source, env) + g.Build() + +def GenerateDSW(dswfile, source, env): + """Generates a Solution/Workspace file based on the version of MSVS that is being used""" + + version_num = 6.0 + if 'MSVS_VERSION' in env: + version_num, suite = msvs_parse_version(env['MSVS_VERSION']) + if version_num >= 7.0: + g = _GenerateV7DSW(dswfile, source, env) + g.Build() + else: + g = _GenerateV6DSW(dswfile, source, env) + g.Build() + + +############################################################################## +# Above here are the classes and functions for generation of +# DSP/DSW/SLN/VCPROJ files. +############################################################################## + +def GetMSVSProjectSuffix(target, source, env, for_signature): + return env['MSVS']['PROJECTSUFFIX'] + +def GetMSVSSolutionSuffix(target, source, env, for_signature): + return env['MSVS']['SOLUTIONSUFFIX'] + +def GenerateProject(target, source, env): + # generate the dsp file, according to the version of MSVS. + builddspfile = target[0] + dspfile = builddspfile.srcnode() + + # this detects whether or not we're using a VariantDir + if not dspfile is builddspfile: + try: + bdsp = open(str(builddspfile), "w+") + except IOError as detail: + print('Unable to open "' + str(dspfile) + '" for writing:',detail,'\n') + raise + + bdsp.write("This is just a placeholder file.\nThe real project file is here:\n%s\n" % dspfile.get_abspath()) + + GenerateDSP(dspfile, source, env) + + if env.get('auto_build_solution', 1): + builddswfile = target[1] + dswfile = builddswfile.srcnode() + + if not dswfile is builddswfile: + + try: + bdsw = open(str(builddswfile), "w+") + except IOError as detail: + print('Unable to open "' + str(dspfile) + '" for writing:',detail,'\n') + raise + + bdsw.write("This is just a placeholder file.\nThe real workspace file is here:\n%s\n" % dswfile.get_abspath()) + + GenerateDSW(dswfile, source, env) + +def GenerateSolution(target, source, env): + GenerateDSW(target[0], source, env) + +def projectEmitter(target, source, env): + """Sets up the DSP dependencies.""" + + # todo: Not sure what sets source to what user has passed as target, + # but this is what happens. When that is fixed, we also won't have + # to make the user always append env['MSVSPROJECTSUFFIX'] to target. + if source[0] == target[0]: + source = [] + + # make sure the suffix is correct for the version of MSVS we're running. + (base, suff) = SCons.Util.splitext(str(target[0])) + suff = env.subst('$MSVSPROJECTSUFFIX') + target[0] = base + suff + + if not source: + source = 'prj_inputs:' + source = source + env.subst('$MSVSSCONSCOM', 1) + source = source + env.subst('$MSVSENCODING', 1) + + # Project file depends on CPPDEFINES and CPPPATH + preprocdefs = xmlify(';'.join(processDefines(env.get('CPPDEFINES', [])))) + includepath_Dirs = processIncludes(env.get('CPPPATH', []), env, None, None) + includepath = xmlify(';'.join([str(x) for x in includepath_Dirs])) + source = source + "; ppdefs:%s incpath:%s"%(preprocdefs, includepath) + + if 'buildtarget' in env and env['buildtarget'] != None: + if SCons.Util.is_String(env['buildtarget']): + source = source + ' "%s"' % env['buildtarget'] + elif SCons.Util.is_List(env['buildtarget']): + for bt in env['buildtarget']: + if SCons.Util.is_String(bt): + source = source + ' "%s"' % bt + else: + try: source = source + ' "%s"' % bt.get_abspath() + except AttributeError: raise SCons.Errors.InternalError("buildtarget can be a string, a node, a list of strings or nodes, or None") + else: + try: source = source + ' "%s"' % env['buildtarget'].get_abspath() + except AttributeError: raise SCons.Errors.InternalError("buildtarget can be a string, a node, a list of strings or nodes, or None") + + if 'outdir' in env and env['outdir'] != None: + if SCons.Util.is_String(env['outdir']): + source = source + ' "%s"' % env['outdir'] + elif SCons.Util.is_List(env['outdir']): + for s in env['outdir']: + if SCons.Util.is_String(s): + source = source + ' "%s"' % s + else: + try: source = source + ' "%s"' % s.get_abspath() + except AttributeError: raise SCons.Errors.InternalError("outdir can be a string, a node, a list of strings or nodes, or None") + else: + try: source = source + ' "%s"' % env['outdir'].get_abspath() + except AttributeError: raise SCons.Errors.InternalError("outdir can be a string, a node, a list of strings or nodes, or None") + + if 'name' in env: + if SCons.Util.is_String(env['name']): + source = source + ' "%s"' % env['name'] + else: + raise SCons.Errors.InternalError("name must be a string") + + if 'variant' in env: + if SCons.Util.is_String(env['variant']): + source = source + ' "%s"' % env['variant'] + elif SCons.Util.is_List(env['variant']): + for variant in env['variant']: + if SCons.Util.is_String(variant): + source = source + ' "%s"' % variant + else: + raise SCons.Errors.InternalError("name must be a string or a list of strings") + else: + raise SCons.Errors.InternalError("variant must be a string or a list of strings") + else: + raise SCons.Errors.InternalError("variant must be specified") + + for s in _DSPGenerator.srcargs: + if s in env: + if SCons.Util.is_String(env[s]): + source = source + ' "%s' % env[s] + elif SCons.Util.is_List(env[s]): + for t in env[s]: + if SCons.Util.is_String(t): + source = source + ' "%s"' % t + else: + raise SCons.Errors.InternalError(s + " must be a string or a list of strings") + else: + raise SCons.Errors.InternalError(s + " must be a string or a list of strings") + + source = source + ' "%s"' % str(target[0]) + source = [SCons.Node.Python.Value(source)] + + targetlist = [target[0]] + sourcelist = source + + if env.get('auto_build_solution', 1): + env['projects'] = [env.File(t).srcnode() for t in targetlist] + t, s = solutionEmitter(target, target, env) + targetlist = targetlist + t + + # Beginning with Visual Studio 2010 for each project file (.vcxproj) we have additional file (.vcxproj.filters) + version_num = 6.0 + if 'MSVS_VERSION' in env: + version_num, suite = msvs_parse_version(env['MSVS_VERSION']) + if version_num >= 10.0: + targetlist.append(targetlist[0] + '.filters') + + return (targetlist, sourcelist) + +def solutionEmitter(target, source, env): + """Sets up the DSW dependencies.""" + + # todo: Not sure what sets source to what user has passed as target, + # but this is what happens. When that is fixed, we also won't have + # to make the user always append env['MSVSSOLUTIONSUFFIX'] to target. + if source[0] == target[0]: + source = [] + + # make sure the suffix is correct for the version of MSVS we're running. + (base, suff) = SCons.Util.splitext(str(target[0])) + suff = env.subst('$MSVSSOLUTIONSUFFIX') + target[0] = base + suff + + if not source: + source = 'sln_inputs:' + + if 'name' in env: + if SCons.Util.is_String(env['name']): + source = source + ' "%s"' % env['name'] + else: + raise SCons.Errors.InternalError("name must be a string") + + if 'variant' in env: + if SCons.Util.is_String(env['variant']): + source = source + ' "%s"' % env['variant'] + elif SCons.Util.is_List(env['variant']): + for variant in env['variant']: + if SCons.Util.is_String(variant): + source = source + ' "%s"' % variant + else: + raise SCons.Errors.InternalError("name must be a string or a list of strings") + else: + raise SCons.Errors.InternalError("variant must be a string or a list of strings") + else: + raise SCons.Errors.InternalError("variant must be specified") + + if 'slnguid' in env: + if SCons.Util.is_String(env['slnguid']): + source = source + ' "%s"' % env['slnguid'] + else: + raise SCons.Errors.InternalError("slnguid must be a string") + + if 'projects' in env: + if SCons.Util.is_String(env['projects']): + source = source + ' "%s"' % env['projects'] + elif SCons.Util.is_List(env['projects']): + for t in env['projects']: + if SCons.Util.is_String(t): + source = source + ' "%s"' % t + + source = source + ' "%s"' % str(target[0]) + source = [SCons.Node.Python.Value(source)] + + return ([target[0]], source) + +projectAction = SCons.Action.Action(GenerateProject, None) + +solutionAction = SCons.Action.Action(GenerateSolution, None) + +projectBuilder = SCons.Builder.Builder(action = '$MSVSPROJECTCOM', + suffix = '$MSVSPROJECTSUFFIX', + emitter = projectEmitter) + +solutionBuilder = SCons.Builder.Builder(action = '$MSVSSOLUTIONCOM', + suffix = '$MSVSSOLUTIONSUFFIX', + emitter = solutionEmitter) + +default_MSVS_SConscript = None + +def generate(env): + """Add Builders and construction variables for Microsoft Visual + Studio project files to an Environment.""" + try: + env['BUILDERS']['MSVSProject'] + except KeyError: + env['BUILDERS']['MSVSProject'] = projectBuilder + + try: + env['BUILDERS']['MSVSSolution'] + except KeyError: + env['BUILDERS']['MSVSSolution'] = solutionBuilder + + env['MSVSPROJECTCOM'] = projectAction + env['MSVSSOLUTIONCOM'] = solutionAction + + if SCons.Script.call_stack: + # XXX Need to find a way to abstract this; the build engine + # shouldn't depend on anything in SCons.Script. + env['MSVSSCONSCRIPT'] = SCons.Script.call_stack[0].sconscript + else: + global default_MSVS_SConscript + if default_MSVS_SConscript is None: + default_MSVS_SConscript = env.File('SConstruct') + env['MSVSSCONSCRIPT'] = default_MSVS_SConscript + + env['MSVSSCONS'] = '"%s" -c "%s"' % (python_executable, getExecScriptMain(env)) + env['MSVSSCONSFLAGS'] = '-C "${MSVSSCONSCRIPT.dir.get_abspath()}" -f ${MSVSSCONSCRIPT.name}' + env['MSVSSCONSCOM'] = '$MSVSSCONS $MSVSSCONSFLAGS' + env['MSVSBUILDCOM'] = '$MSVSSCONSCOM "$MSVSBUILDTARGET"' + env['MSVSREBUILDCOM'] = '$MSVSSCONSCOM "$MSVSBUILDTARGET"' + env['MSVSCLEANCOM'] = '$MSVSSCONSCOM -c "$MSVSBUILDTARGET"' + + # Set-up ms tools paths for default version + msvc_setup_env_once(env) + + if 'MSVS_VERSION' in env: + version_num, suite = msvs_parse_version(env['MSVS_VERSION']) + else: + (version_num, suite) = (7.0, None) # guess at a default + if 'MSVS' not in env: + env['MSVS'] = {} + if (version_num < 7.0): + env['MSVS']['PROJECTSUFFIX'] = '.dsp' + env['MSVS']['SOLUTIONSUFFIX'] = '.dsw' + elif (version_num < 10.0): + env['MSVS']['PROJECTSUFFIX'] = '.vcproj' + env['MSVS']['SOLUTIONSUFFIX'] = '.sln' + else: + env['MSVS']['PROJECTSUFFIX'] = '.vcxproj' + env['MSVS']['SOLUTIONSUFFIX'] = '.sln' + + if (version_num >= 10.0): + env['MSVSENCODING'] = 'utf-8' + else: + env['MSVSENCODING'] = 'Windows-1252' + + env['GET_MSVSPROJECTSUFFIX'] = GetMSVSProjectSuffix + env['GET_MSVSSOLUTIONSUFFIX'] = GetMSVSSolutionSuffix + env['MSVSPROJECTSUFFIX'] = '${GET_MSVSPROJECTSUFFIX}' + env['MSVSSOLUTIONSUFFIX'] = '${GET_MSVSSOLUTIONSUFFIX}' + env['SCONS_HOME'] = os.environ.get('SCONS_HOME') + +def exists(env): + return msvc_exists(env) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/mwcc.py b/tools/scons/scons-local-3.0.5/SCons/Tool/mwcc.py new file mode 100755 index 0000000000..bc1e62cf56 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/mwcc.py @@ -0,0 +1,207 @@ +"""SCons.Tool.mwcc + +Tool-specific initialization for the Metrowerks CodeWarrior compiler. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/mwcc.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os +import os.path + +import SCons.Util + +def set_vars(env): + """Set MWCW_VERSION, MWCW_VERSIONS, and some codewarrior environment vars + + MWCW_VERSIONS is set to a list of objects representing installed versions + + MWCW_VERSION is set to the version object that will be used for building. + MWCW_VERSION can be set to a string during Environment + construction to influence which version is chosen, otherwise + the latest one from MWCW_VERSIONS is used. + + Returns true if at least one version is found, false otherwise + """ + desired = env.get('MWCW_VERSION', '') + + # return right away if the variables are already set + if isinstance(desired, MWVersion): + return 1 + elif desired is None: + return 0 + + versions = find_versions() + version = None + + if desired: + for v in versions: + if str(v) == desired: + version = v + elif versions: + version = versions[-1] + + env['MWCW_VERSIONS'] = versions + env['MWCW_VERSION'] = version + + if version is None: + return 0 + + env.PrependENVPath('PATH', version.clpath) + env.PrependENVPath('PATH', version.dllpath) + ENV = env['ENV'] + ENV['CWFolder'] = version.path + ENV['LM_LICENSE_FILE'] = version.license + plus = lambda x: '+%s' % x + ENV['MWCIncludes'] = os.pathsep.join(map(plus, version.includes)) + ENV['MWLibraries'] = os.pathsep.join(map(plus, version.libs)) + return 1 + + +def find_versions(): + """Return a list of MWVersion objects representing installed versions""" + versions = [] + + ### This function finds CodeWarrior by reading from the registry on + ### Windows. Some other method needs to be implemented for other + ### platforms, maybe something that calls env.WhereIs('mwcc') + + if SCons.Util.can_read_reg: + try: + HLM = SCons.Util.HKEY_LOCAL_MACHINE + product = 'SOFTWARE\\Metrowerks\\CodeWarrior\\Product Versions' + product_key = SCons.Util.RegOpenKeyEx(HLM, product) + + i = 0 + while True: + name = product + '\\' + SCons.Util.RegEnumKey(product_key, i) + name_key = SCons.Util.RegOpenKeyEx(HLM, name) + + try: + version = SCons.Util.RegQueryValueEx(name_key, 'VERSION') + path = SCons.Util.RegQueryValueEx(name_key, 'PATH') + mwv = MWVersion(version[0], path[0], 'Win32-X86') + versions.append(mwv) + except SCons.Util.RegError: + pass + + i = i + 1 + + except SCons.Util.RegError: + pass + + return versions + + +class MWVersion(object): + def __init__(self, version, path, platform): + self.version = version + self.path = path + self.platform = platform + self.clpath = os.path.join(path, 'Other Metrowerks Tools', + 'Command Line Tools') + self.dllpath = os.path.join(path, 'Bin') + + # The Metrowerks tools don't store any configuration data so they + # are totally dumb when it comes to locating standard headers, + # libraries, and other files, expecting all the information + # to be handed to them in environment variables. The members set + # below control what information scons injects into the environment + + ### The paths below give a normal build environment in CodeWarrior for + ### Windows, other versions of CodeWarrior might need different paths. + + msl = os.path.join(path, 'MSL') + support = os.path.join(path, '%s Support' % platform) + + self.license = os.path.join(path, 'license.dat') + self.includes = [msl, support] + self.libs = [msl, support] + + def __str__(self): + return self.version + + +CSuffixes = ['.c', '.C'] +CXXSuffixes = ['.cc', '.cpp', '.cxx', '.c++', '.C++'] + + +def generate(env): + """Add Builders and construction variables for the mwcc to an Environment.""" + import SCons.Defaults + import SCons.Tool + + set_vars(env) + + static_obj, shared_obj = SCons.Tool.createObjBuilders(env) + + for suffix in CSuffixes: + static_obj.add_action(suffix, SCons.Defaults.CAction) + shared_obj.add_action(suffix, SCons.Defaults.ShCAction) + + for suffix in CXXSuffixes: + static_obj.add_action(suffix, SCons.Defaults.CXXAction) + shared_obj.add_action(suffix, SCons.Defaults.ShCXXAction) + + env['CCCOMFLAGS'] = '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -nolink -o $TARGET $SOURCES' + + env['CC'] = 'mwcc' + env['CCCOM'] = '$CC $CFLAGS $CCFLAGS $CCCOMFLAGS' + + env['CXX'] = 'mwcc' + env['CXXCOM'] = '$CXX $CXXFLAGS $CCCOMFLAGS' + + env['SHCC'] = '$CC' + env['SHCCFLAGS'] = '$CCFLAGS' + env['SHCFLAGS'] = '$CFLAGS' + env['SHCCCOM'] = '$SHCC $SHCFLAGS $SHCCFLAGS $CCCOMFLAGS' + + env['SHCXX'] = '$CXX' + env['SHCXXFLAGS'] = '$CXXFLAGS' + env['SHCXXCOM'] = '$SHCXX $SHCXXFLAGS $CCCOMFLAGS' + + env['CFILESUFFIX'] = '.c' + env['CXXFILESUFFIX'] = '.cpp' + env['CPPDEFPREFIX'] = '-D' + env['CPPDEFSUFFIX'] = '' + env['INCPREFIX'] = '-I' + env['INCSUFFIX'] = '' + + #env['PCH'] = ? + #env['PCHSTOP'] = ? + + +def exists(env): + return set_vars(env) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/mwld.py b/tools/scons/scons-local-3.0.5/SCons/Tool/mwld.py new file mode 100755 index 0000000000..f671319c2c --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/mwld.py @@ -0,0 +1,108 @@ +"""SCons.Tool.mwld + +Tool-specific initialization for the Metrowerks CodeWarrior linker. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/mwld.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Tool + + +def generate(env): + """Add Builders and construction variables for lib to an Environment.""" + SCons.Tool.createStaticLibBuilder(env) + SCons.Tool.createSharedLibBuilder(env) + SCons.Tool.createProgBuilder(env) + + env['AR'] = 'mwld' + env['ARCOM'] = '$AR $ARFLAGS -library -o $TARGET $SOURCES' + + env['LIBDIRPREFIX'] = '-L' + env['LIBDIRSUFFIX'] = '' + env['LIBLINKPREFIX'] = '-l' + env['LIBLINKSUFFIX'] = '.lib' + + env['LINK'] = 'mwld' + env['LINKCOM'] = '$LINK $LINKFLAGS -o $TARGET $SOURCES $_LIBDIRFLAGS $_LIBFLAGS' + + env['SHLINK'] = '$LINK' + env['SHLINKFLAGS'] = '$LINKFLAGS' + env['SHLINKCOM'] = shlib_action + env['SHLIBEMITTER']= shlib_emitter + env['LDMODULEEMITTER']= shlib_emitter + + +def exists(env): + import SCons.Tool.mwcc + return SCons.Tool.mwcc.set_vars(env) + + +def shlib_generator(target, source, env, for_signature): + cmd = ['$SHLINK', '$SHLINKFLAGS', '-shared'] + + no_import_lib = env.get('no_import_lib', 0) + if no_import_lib: cmd.extend('-noimplib') + + dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX') + if dll: cmd.extend(['-o', dll]) + + implib = env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX') + if implib: cmd.extend(['-implib', implib.get_string(for_signature)]) + + cmd.extend(['$SOURCES', '$_LIBDIRFLAGS', '$_LIBFLAGS']) + + return [cmd] + + +def shlib_emitter(target, source, env): + dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX') + no_import_lib = env.get('no_import_lib', 0) + + if not dll: + raise SCons.Errors.UserError("A shared library should have exactly one target with the suffix: %s" % env.subst("$SHLIBSUFFIX")) + + if not no_import_lib and \ + not env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX'): + + # Append an import library to the list of targets. + target.append(env.ReplaceIxes(dll, + 'SHLIBPREFIX', 'SHLIBSUFFIX', + 'LIBPREFIX', 'LIBSUFFIX')) + + return target, source + + +shlib_action = SCons.Action.Action(shlib_generator, generator=1) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/nasm.py b/tools/scons/scons-local-3.0.5/SCons/Tool/nasm.py new file mode 100755 index 0000000000..1615b6b970 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/nasm.py @@ -0,0 +1,72 @@ +"""SCons.Tool.nasm + +Tool-specific initialization for nasm, the famous Netwide Assembler. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/nasm.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Defaults +import SCons.Tool +import SCons.Util + +ASSuffixes = ['.s', '.asm', '.ASM'] +ASPPSuffixes = ['.spp', '.SPP', '.sx'] +if SCons.Util.case_sensitive_suffixes('.s', '.S'): + ASPPSuffixes.extend(['.S']) +else: + ASSuffixes.extend(['.S']) + +def generate(env): + """Add Builders and construction variables for nasm to an Environment.""" + static_obj, shared_obj = SCons.Tool.createObjBuilders(env) + + for suffix in ASSuffixes: + static_obj.add_action(suffix, SCons.Defaults.ASAction) + static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter) + + for suffix in ASPPSuffixes: + static_obj.add_action(suffix, SCons.Defaults.ASPPAction) + static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter) + + env['AS'] = 'nasm' + env['ASFLAGS'] = SCons.Util.CLVar('') + env['ASPPFLAGS'] = '$ASFLAGS' + env['ASCOM'] = '$AS $ASFLAGS -o $TARGET $SOURCES' + env['ASPPCOM'] = '$CC $ASPPFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES' + +def exists(env): + return env.Detect('nasm') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/__init__.py b/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/__init__.py new file mode 100755 index 0000000000..af60e8b264 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/__init__.py @@ -0,0 +1,322 @@ +"""SCons.Tool.Packaging + +SCons Packaging Tool. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +__revision__ = "src/engine/SCons/Tool/packaging/__init__.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Defaults +import SCons.Environment +from SCons.Variables import * +from SCons.Errors import * +from SCons.Util import is_List, make_path_relative +from SCons.Warnings import warn, Warning + +import os +import imp + +__all__ = [ + 'src_targz', 'src_tarbz2', 'src_xz', 'src_zip', + 'targz', 'tarbz2', 'xz', 'zip', + 'rpm', 'msi', 'ipk', +] + +# +# Utility and Builder function +# +def Tag(env, target, source, *more_tags, **kw_tags): + """ Tag a file with the given arguments, just sets the accordingly named + attribute on the file object. + + TODO: FIXME + """ + if not target: + target=source + first_tag=None + else: + first_tag=source + + if first_tag: + kw_tags[first_tag[0]] = '' + + if len(kw_tags) == 0 and len(more_tags) == 0: + raise UserError("No tags given.") + + # XXX: sanity checks + for x in more_tags: + kw_tags[x] = '' + + if not SCons.Util.is_List(target): + target=[target] + else: + # hmm, sometimes the target list, is a list of a list + # make sure it is flattened prior to processing. + # TODO: perhaps some bug ?!? + target=env.Flatten(target) + + for t in target: + for (k,v) in kw_tags.items(): + # all file tags have to start with PACKAGING_, so we can later + # differentiate between "normal" object attributes and the + # packaging attributes. As the user should not be bothered with + # that, the prefix will be added here if missing. + if k[:10] != 'PACKAGING_': + k='PACKAGING_'+k + t.Tag(k, v) + +def Package(env, target=None, source=None, **kw): + """ Entry point for the package tool. + """ + # check if we need to find the source files ourself + if not source: + source = env.FindInstalledFiles() + + if len(source)==0: + raise UserError("No source for Package() given") + + # decide which types of packages shall be built. Can be defined through + # four mechanisms: command line argument, keyword argument, + # environment argument and default selection( zip or tar.gz ) in that + # order. + try: kw['PACKAGETYPE']=env['PACKAGETYPE'] + except KeyError: pass + + if not kw.get('PACKAGETYPE'): + from SCons.Script import GetOption + kw['PACKAGETYPE'] = GetOption('package_type') + + if kw['PACKAGETYPE'] is None: + if 'Tar' in env['BUILDERS']: + kw['PACKAGETYPE']='targz' + elif 'Zip' in env['BUILDERS']: + kw['PACKAGETYPE']='zip' + else: + raise UserError("No type for Package() given") + + PACKAGETYPE=kw['PACKAGETYPE'] + if not is_List(PACKAGETYPE): + PACKAGETYPE=PACKAGETYPE.split(',') + + # load the needed packagers. + def load_packager(type): + try: + file,path,desc=imp.find_module(type, __path__) + return imp.load_module(type, file, path, desc) + except ImportError as e: + raise EnvironmentError("packager %s not available: %s"%(type,str(e))) + + packagers=list(map(load_packager, PACKAGETYPE)) + + # set up targets and the PACKAGEROOT + try: + # fill up the target list with a default target name until the PACKAGETYPE + # list is of the same size as the target list. + if not target: target = [] + + size_diff = len(PACKAGETYPE)-len(target) + default_name = "%(NAME)s-%(VERSION)s" + + if size_diff>0: + default_target = default_name%kw + target.extend( [default_target]*size_diff ) + + if 'PACKAGEROOT' not in kw: + kw['PACKAGEROOT'] = default_name%kw + + except KeyError as e: + raise SCons.Errors.UserError( "Missing Packagetag '%s'"%e.args[0] ) + + # setup the source files + source=env.arg2nodes(source, env.fs.Entry) + + # call the packager to setup the dependencies. + targets=[] + try: + for packager in packagers: + t=[target.pop(0)] + t=packager.package(env,t,source, **kw) + targets.extend(t) + + assert( len(target) == 0 ) + + except KeyError as e: + raise SCons.Errors.UserError( "Missing Packagetag '%s' for %s packager"\ + % (e.args[0],packager.__name__) ) + except TypeError as e: + # this exception means that a needed argument for the packager is + # missing. As our packagers get their "tags" as named function + # arguments we need to find out which one is missing. + #TODO: getargspec deprecated in Py3. cleanup when Py2.7 dropped. + try: + from inspect import getfullargspec + argspec = getfullargspec(packager.package) + except ImportError: + from inspect import getargspec + argspec = getargspec(packager.package) + args = argspec.args + if argspec.defaults: + # throw away arguments with default values + args = args[:-len(argspec.defaults)] + args.remove('env') + args.remove('target') + args.remove('source') + # now remove any args for which we have a value in kw. + args = [x for x in args if x not in kw] + + if len(args)==0: + raise # must be a different error, so re-raise + elif len(args)==1: + raise SCons.Errors.UserError( "Missing Packagetag '%s' for %s packager"\ + % (args[0],packager.__name__) ) + else: + raise SCons.Errors.UserError( "Missing Packagetags '%s' for %s packager"\ + % (", ".join(args),packager.__name__) ) + + target=env.arg2nodes(target, env.fs.Entry) + targets.extend(env.Alias( 'package', targets )) + return targets + +# +# SCons tool initialization functions +# + +added = None + +def generate(env): + from SCons.Script import AddOption + global added + if not added: + added = 1 + AddOption('--package-type', + dest='package_type', + default=None, + type="string", + action="store", + help='The type of package to create.') + + try: + env['BUILDERS']['Package'] + env['BUILDERS']['Tag'] + except KeyError: + env['BUILDERS']['Package'] = Package + env['BUILDERS']['Tag'] = Tag + +def exists(env): + return 1 + +# XXX +def options(opts): + opts.AddVariables( + EnumVariable( 'PACKAGETYPE', + 'the type of package to create.', + None, allowed_values=list(map( str, __all__ )), + ignorecase=2 + ) + ) + +# +# Internal utility functions +# + +def copy_attr(f1, f2): + """ copies the special packaging file attributes from f1 to f2. + """ + copyit = lambda x: not hasattr(f2, x) and x[:10] == 'PACKAGING_' + if f1._tags: + pattrs = [tag for tag in f1._tags if copyit(tag)] + for attr in pattrs: + f2.Tag(attr, f1.GetTag(attr)) + +def putintopackageroot(target, source, env, pkgroot, honor_install_location=1): + """ Uses the CopyAs builder to copy all source files to the directory given + in pkgroot. + + If honor_install_location is set and the copied source file has an + PACKAGING_INSTALL_LOCATION attribute, the PACKAGING_INSTALL_LOCATION is + used as the new name of the source file under pkgroot. + + The source file will not be copied if it is already under the the pkgroot + directory. + + All attributes of the source file will be copied to the new file. + """ + # make sure the packageroot is a Dir object. + if SCons.Util.is_String(pkgroot): pkgroot=env.Dir(pkgroot) + if not SCons.Util.is_List(source): source=[source] + + new_source = [] + for file in source: + if SCons.Util.is_String(file): file = env.File(file) + + if file.is_under(pkgroot): + new_source.append(file) + else: + if file.GetTag('PACKAGING_INSTALL_LOCATION') and\ + honor_install_location: + new_name=make_path_relative(file.GetTag('PACKAGING_INSTALL_LOCATION')) + else: + new_name=make_path_relative(file.get_path()) + + new_file=pkgroot.File(new_name) + new_file=env.CopyAs(new_file, file)[0] + copy_attr(file, new_file) + new_source.append(new_file) + + return (target, new_source) + +def stripinstallbuilder(target, source, env): + """ Strips the install builder action from the source list and stores + the final installation location as the "PACKAGING_INSTALL_LOCATION" of + the source of the source file. This effectively removes the final installed + files from the source list while remembering the installation location. + + It also warns about files which have no install builder attached. + """ + def has_no_install_location(file): + return not (file.has_builder() and hasattr(file.builder, 'name') + and file.builder.name in ["InstallBuilder", "InstallAsBuilder"]) + + + if len([src for src in source if has_no_install_location(src)]): + warn(Warning, "there are files to package which have no\ + InstallBuilder attached, this might lead to irreproducible packages") + + n_source=[] + for s in source: + if has_no_install_location(s): + n_source.append(s) + else: + for ss in s.sources: + n_source.append(ss) + copy_attr(s, ss) + ss.Tag('PACKAGING_INSTALL_LOCATION', s.get_path()) + + return (target, n_source) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/ipk.py b/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/ipk.py new file mode 100755 index 0000000000..2ebc1689a9 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/ipk.py @@ -0,0 +1,189 @@ +"""SCons.Tool.Packaging.ipk +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/packaging/ipk.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os + +import SCons.Builder +import SCons.Node.FS +import SCons.Util + +from SCons.Tool.packaging import stripinstallbuilder, putintopackageroot + +def package(env, target, source, PACKAGEROOT, NAME, VERSION, DESCRIPTION, + SUMMARY, X_IPK_PRIORITY, X_IPK_SECTION, SOURCE_URL, + X_IPK_MAINTAINER, X_IPK_DEPENDS, **kw): + """ This function prepares the packageroot directory for packaging with the + ipkg builder. + """ + SCons.Tool.Tool('ipkg').generate(env) + + # setup the Ipkg builder + bld = env['BUILDERS']['Ipkg'] + target, source = stripinstallbuilder(target, source, env) + target, source = putintopackageroot(target, source, env, PACKAGEROOT) + + # This should be overrideable from the construction environment, + # which it is by using ARCHITECTURE=. + # Guessing based on what os.uname() returns at least allows it + # to work for both i386 and x86_64 Linux systems. + archmap = { + 'i686' : 'i386', + 'i586' : 'i386', + 'i486' : 'i386', + } + + buildarchitecture = os.uname()[4] + buildarchitecture = archmap.get(buildarchitecture, buildarchitecture) + + if 'ARCHITECTURE' in kw: + buildarchitecture = kw['ARCHITECTURE'] + + # setup the kw to contain the mandatory arguments to this function. + # do this before calling any builder or setup function + loc=locals() + del loc['kw'] + kw.update(loc) + del kw['source'], kw['target'], kw['env'] + + # generate the specfile + specfile = gen_ipk_dir(PACKAGEROOT, source, env, kw) + + # override the default target. + if str(target[0])=="%s-%s"%(NAME, VERSION): + target=[ "%s_%s_%s.ipk"%(NAME, VERSION, buildarchitecture) ] + + # now apply the Ipkg builder + return bld(env, target, specfile, **kw) + +def gen_ipk_dir(proot, source, env, kw): + # make sure the packageroot is a Dir object. + if SCons.Util.is_String(proot): proot=env.Dir(proot) + + # create the specfile builder + s_bld=SCons.Builder.Builder( + action = build_specfiles, + ) + + # create the specfile targets + spec_target=[] + control=proot.Dir('CONTROL') + spec_target.append(control.File('control')) + spec_target.append(control.File('conffiles')) + spec_target.append(control.File('postrm')) + spec_target.append(control.File('prerm')) + spec_target.append(control.File('postinst')) + spec_target.append(control.File('preinst')) + + # apply the builder to the specfile targets + s_bld(env, spec_target, source, **kw) + + # the packageroot directory does now contain the specfiles. + return proot + +def build_specfiles(source, target, env): + """ Filter the targets for the needed files and use the variables in env + to create the specfile. + """ + # + # At first we care for the CONTROL/control file, which is the main file for ipk. + # + # For this we need to open multiple files in random order, so we store into + # a dict so they can be easily accessed. + # + # + opened_files={} + def open_file(needle, haystack): + try: + return opened_files[needle] + except KeyError: + files = filter(lambda x: x.get_path().rfind(needle) != -1, haystack) + # Py3: filter returns an iterable, not a list + file = list(files)[0] + opened_files[needle]=open(file.get_abspath(), 'w') + return opened_files[needle] + + control_file=open_file('control', target) + + if 'X_IPK_DESCRIPTION' not in env: + env['X_IPK_DESCRIPTION']="%s\n %s"%(env['SUMMARY'], + env['DESCRIPTION'].replace('\n', '\n ')) + + + content = """ +Package: $NAME +Version: $VERSION +Priority: $X_IPK_PRIORITY +Section: $X_IPK_SECTION +Source: $SOURCE_URL +Architecture: $ARCHITECTURE +Maintainer: $X_IPK_MAINTAINER +Depends: $X_IPK_DEPENDS +Description: $X_IPK_DESCRIPTION +""" + + control_file.write(env.subst(content)) + + # + # now handle the various other files, which purpose it is to set post-, + # pre-scripts and mark files as config files. + # + # We do so by filtering the source files for files which are marked with + # the "config" tag and afterwards we do the same for x_ipk_postrm, + # x_ipk_prerm, x_ipk_postinst and x_ipk_preinst tags. + # + # The first one will write the name of the file into the file + # CONTROL/configfiles, the latter add the content of the x_ipk_* variable + # into the same named file. + # + for f in [x for x in source if 'PACKAGING_CONFIG' in dir(x)]: + config=open_file('conffiles') + config.write(f.PACKAGING_INSTALL_LOCATION) + config.write('\n') + + for str in 'POSTRM PRERM POSTINST PREINST'.split(): + name="PACKAGING_X_IPK_%s"%str + for f in [x for x in source if name in dir(x)]: + file=open_file(name) + file.write(env[str]) + + # + # close all opened files + for f in list(opened_files.values()): + f.close() + + # call a user specified function + if 'CHANGE_SPECFILE' in env: + content += env['CHANGE_SPECFILE'](target) + + return 0 + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/msi.py b/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/msi.py new file mode 100755 index 0000000000..fbb8b21f30 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/msi.py @@ -0,0 +1,526 @@ +"""SCons.Tool.packaging.msi + +The msi packager. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +__revision__ = "src/engine/SCons/Tool/packaging/msi.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os +import SCons +from SCons.Action import Action +from SCons.Builder import Builder + +from xml.dom.minidom import * +from xml.sax.saxutils import escape + +from SCons.Tool.packaging import stripinstallbuilder + +# +# Utility functions +# +def convert_to_id(s, id_set): + """ Some parts of .wxs need an Id attribute (for example: The File and + Directory directives. The charset is limited to A-Z, a-z, digits, + underscores, periods. Each Id must begin with a letter or with a + underscore. Google for "CNDL0015" for information about this. + + Requirements: + * the string created must only contain chars from the target charset. + * the string created must have a minimal editing distance from the + original string. + * the string created must be unique for the whole .wxs file. + + Observation: + * There are 62 chars in the charset. + + Idea: + * filter out forbidden characters. Check for a collision with the help + of the id_set. Add the number of the number of the collision at the + end of the created string. Furthermore care for a correct start of + the string. + """ + charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxyz0123456789_.' + if s[0] in '0123456789.': + s = '_' + s + id = ''.join([c for c in s if c in charset]) + + # did we already generate an id for this file? + try: + return id_set[id][s] + except KeyError: + # no we did not, so initialize with the id + if id not in id_set: id_set[id] = { s : id } + # there is a collision, generate an id which is unique by appending + # the collision number + else: id_set[id][s] = id + str(len(id_set[id])) + + return id_set[id][s] + +def is_dos_short_file_name(file): + """ Examine if the given file is in the 8.3 form. + """ + fname, ext = os.path.splitext(file) + proper_ext = len(ext) == 0 or (2 <= len(ext) <= 4) # the ext contains the dot + proper_fname = file.isupper() and len(fname) <= 8 + + return proper_ext and proper_fname + +def gen_dos_short_file_name(file, filename_set): + """ See http://support.microsoft.com/default.aspx?scid=kb;en-us;Q142982 + + These are no complete 8.3 dos short names. The ~ char is missing and + replaced with one character from the filename. WiX warns about such + filenames, since a collision might occur. Google for "CNDL1014" for + more information. + """ + # guard this to not confuse the generation + if is_dos_short_file_name(file): + return file + + fname, ext = os.path.splitext(file) # ext contains the dot + + # first try if it suffices to convert to upper + file = file.upper() + if is_dos_short_file_name(file): + return file + + # strip forbidden characters. + forbidden = '."/[]:;=, ' + fname = ''.join([c for c in fname if c not in forbidden]) + + # check if we already generated a filename with the same number: + # thisis1.txt, thisis2.txt etc. + duplicate, num = not None, 1 + while duplicate: + shortname = "%s%s" % (fname[:8-len(str(num))].upper(), str(num)) + if len(ext) >= 2: + shortname = "%s%s" % (shortname, ext[:4].upper()) + + duplicate, num = shortname in filename_set, num+1 + + assert( is_dos_short_file_name(shortname) ), 'shortname is %s, longname is %s' % (shortname, file) + filename_set.append(shortname) + return shortname + +def create_feature_dict(files): + """ X_MSI_FEATURE and doc FileTag's can be used to collect files in a + hierarchy. This function collects the files into this hierarchy. + """ + dict = {} + + def add_to_dict( feature, file ): + if not SCons.Util.is_List( feature ): + feature = [ feature ] + + for f in feature: + if f not in dict: + dict[ f ] = [ file ] + else: + dict[ f ].append( file ) + + for file in files: + if hasattr( file, 'PACKAGING_X_MSI_FEATURE' ): + add_to_dict(file.PACKAGING_X_MSI_FEATURE, file) + elif hasattr( file, 'PACKAGING_DOC' ): + add_to_dict( 'PACKAGING_DOC', file ) + else: + add_to_dict( 'default', file ) + + return dict + +def generate_guids(root): + """ generates globally unique identifiers for parts of the xml which need + them. + + Component tags have a special requirement. Their UUID is only allowed to + change if the list of their contained resources has changed. This allows + for clean removal and proper updates. + + To handle this requirement, the uuid is generated with an md5 hashing the + whole subtree of a xml node. + """ + from hashlib import md5 + + # specify which tags need a guid and in which attribute this should be stored. + needs_id = { 'Product' : 'Id', + 'Package' : 'Id', + 'Component' : 'Guid', + } + + # find all XMl nodes matching the key, retrieve their attribute, hash their + # subtree, convert hash to string and add as a attribute to the xml node. + for (key,value) in needs_id.items(): + node_list = root.getElementsByTagName(key) + attribute = value + for node in node_list: + hash = md5(node.toxml()).hexdigest() + hash_str = '%s-%s-%s-%s-%s' % ( hash[:8], hash[8:12], hash[12:16], hash[16:20], hash[20:] ) + node.attributes[attribute] = hash_str + + + +def string_wxsfile(target, source, env): + return "building WiX file %s"%( target[0].path ) + +def build_wxsfile(target, source, env): + """ Compiles a .wxs file from the keywords given in env['msi_spec'] and + by analyzing the tree of source nodes and their tags. + """ + file = open(target[0].get_abspath(), 'w') + + try: + # Create a document with the Wix root tag + doc = Document() + root = doc.createElement( 'Wix' ) + root.attributes['xmlns']='http://schemas.microsoft.com/wix/2003/01/wi' + doc.appendChild( root ) + + filename_set = [] # this is to circumvent duplicates in the shortnames + id_set = {} # this is to circumvent duplicates in the ids + + # Create the content + build_wxsfile_header_section(root, env) + build_wxsfile_file_section(root, source, env['NAME'], env['VERSION'], env['VENDOR'], filename_set, id_set) + generate_guids(root) + build_wxsfile_features_section(root, source, env['NAME'], env['VERSION'], env['SUMMARY'], id_set) + build_wxsfile_default_gui(root) + build_license_file(target[0].get_dir(), env) + + # write the xml to a file + file.write( doc.toprettyxml() ) + + # call a user specified function + if 'CHANGE_SPECFILE' in env: + env['CHANGE_SPECFILE'](target, source) + + except KeyError as e: + raise SCons.Errors.UserError( '"%s" package field for MSI is missing.' % e.args[0] ) + +# +# setup function +# +def create_default_directory_layout(root, NAME, VERSION, VENDOR, filename_set): + """ Create the wix default target directory layout and return the innermost + directory. + + We assume that the XML tree delivered in the root argument already contains + the Product tag. + + Everything is put under the PFiles directory property defined by WiX. + After that a directory with the 'VENDOR' tag is placed and then a + directory with the name of the project and its VERSION. This leads to the + following TARGET Directory Layout: + C:\\\\ + Example: C:\Programme\Company\Product-1.2\ + """ + doc = Document() + d1 = doc.createElement( 'Directory' ) + d1.attributes['Id'] = 'TARGETDIR' + d1.attributes['Name'] = 'SourceDir' + + d2 = doc.createElement( 'Directory' ) + d2.attributes['Id'] = 'ProgramFilesFolder' + d2.attributes['Name'] = 'PFiles' + + d3 = doc.createElement( 'Directory' ) + d3.attributes['Id'] = 'VENDOR_folder' + d3.attributes['Name'] = escape( gen_dos_short_file_name( VENDOR, filename_set ) ) + d3.attributes['LongName'] = escape( VENDOR ) + + d4 = doc.createElement( 'Directory' ) + project_folder = "%s-%s" % ( NAME, VERSION ) + d4.attributes['Id'] = 'MY_DEFAULT_FOLDER' + d4.attributes['Name'] = escape( gen_dos_short_file_name( project_folder, filename_set ) ) + d4.attributes['LongName'] = escape( project_folder ) + + d1.childNodes.append( d2 ) + d2.childNodes.append( d3 ) + d3.childNodes.append( d4 ) + + root.getElementsByTagName('Product')[0].childNodes.append( d1 ) + + return d4 + +# +# mandatory and optional file tags +# +def build_wxsfile_file_section(root, files, NAME, VERSION, VENDOR, filename_set, id_set): + """ Builds the Component sections of the wxs file with their included files. + + Files need to be specified in 8.3 format and in the long name format, long + filenames will be converted automatically. + + Features are specficied with the 'X_MSI_FEATURE' or 'DOC' FileTag. + """ + root = create_default_directory_layout( root, NAME, VERSION, VENDOR, filename_set ) + components = create_feature_dict( files ) + factory = Document() + + def get_directory( node, dir ): + """ Returns the node under the given node representing the directory. + + Returns the component node if dir is None or empty. + """ + if dir == '' or not dir: + return node + + Directory = node + dir_parts = dir.split(os.path.sep) + + # to make sure that our directory ids are unique, the parent folders are + # consecutively added to upper_dir + upper_dir = '' + + # walk down the xml tree finding parts of the directory + dir_parts = [d for d in dir_parts if d != ''] + for d in dir_parts[:]: + already_created = [c for c in Directory.childNodes + if c.nodeName == 'Directory' + and c.attributes['LongName'].value == escape(d)] + + if already_created: + Directory = already_created[0] + dir_parts.remove(d) + upper_dir += d + else: + break + + for d in dir_parts: + nDirectory = factory.createElement( 'Directory' ) + nDirectory.attributes['LongName'] = escape( d ) + nDirectory.attributes['Name'] = escape( gen_dos_short_file_name( d, filename_set ) ) + upper_dir += d + nDirectory.attributes['Id'] = convert_to_id( upper_dir, id_set ) + + Directory.childNodes.append( nDirectory ) + Directory = nDirectory + + return Directory + + for file in files: + drive, path = os.path.splitdrive( file.PACKAGING_INSTALL_LOCATION ) + filename = os.path.basename( path ) + dirname = os.path.dirname( path ) + + h = { + # tagname : default value + 'PACKAGING_X_MSI_VITAL' : 'yes', + 'PACKAGING_X_MSI_FILEID' : convert_to_id(filename, id_set), + 'PACKAGING_X_MSI_LONGNAME' : filename, + 'PACKAGING_X_MSI_SHORTNAME' : gen_dos_short_file_name(filename, filename_set), + 'PACKAGING_X_MSI_SOURCE' : file.get_path(), + } + + # fill in the default tags given above. + for k,v in [ (k, v) for (k,v) in h.items() if not hasattr(file, k) ]: + setattr( file, k, v ) + + File = factory.createElement( 'File' ) + File.attributes['LongName'] = escape( file.PACKAGING_X_MSI_LONGNAME ) + File.attributes['Name'] = escape( file.PACKAGING_X_MSI_SHORTNAME ) + File.attributes['Source'] = escape( file.PACKAGING_X_MSI_SOURCE ) + File.attributes['Id'] = escape( file.PACKAGING_X_MSI_FILEID ) + File.attributes['Vital'] = escape( file.PACKAGING_X_MSI_VITAL ) + + # create the Tag under which this file should appear + Component = factory.createElement('Component') + Component.attributes['DiskId'] = '1' + Component.attributes['Id'] = convert_to_id( filename, id_set ) + + # hang the component node under the root node and the file node + # under the component node. + Directory = get_directory( root, dirname ) + Directory.childNodes.append( Component ) + Component.childNodes.append( File ) + +# +# additional functions +# +def build_wxsfile_features_section(root, files, NAME, VERSION, SUMMARY, id_set): + """ This function creates the tag based on the supplied xml tree. + + This is achieved by finding all s and adding them to a default target. + + It should be called after the tree has been built completly. We assume + that a MY_DEFAULT_FOLDER Property is defined in the wxs file tree. + + Furthermore a top-level with the name and VERSION of the software will be created. + + An PACKAGING_X_MSI_FEATURE can either be a string, where the feature + DESCRIPTION will be the same as its title or a Tuple, where the first + part will be its title and the second its DESCRIPTION. + """ + factory = Document() + Feature = factory.createElement('Feature') + Feature.attributes['Id'] = 'complete' + Feature.attributes['ConfigurableDirectory'] = 'MY_DEFAULT_FOLDER' + Feature.attributes['Level'] = '1' + Feature.attributes['Title'] = escape( '%s %s' % (NAME, VERSION) ) + Feature.attributes['Description'] = escape( SUMMARY ) + Feature.attributes['Display'] = 'expand' + + for (feature, files) in create_feature_dict(files).items(): + SubFeature = factory.createElement('Feature') + SubFeature.attributes['Level'] = '1' + + if SCons.Util.is_Tuple(feature): + SubFeature.attributes['Id'] = convert_to_id( feature[0], id_set ) + SubFeature.attributes['Title'] = escape(feature[0]) + SubFeature.attributes['Description'] = escape(feature[1]) + else: + SubFeature.attributes['Id'] = convert_to_id( feature, id_set ) + if feature=='default': + SubFeature.attributes['Description'] = 'Main Part' + SubFeature.attributes['Title'] = 'Main Part' + elif feature=='PACKAGING_DOC': + SubFeature.attributes['Description'] = 'Documentation' + SubFeature.attributes['Title'] = 'Documentation' + else: + SubFeature.attributes['Description'] = escape(feature) + SubFeature.attributes['Title'] = escape(feature) + + # build the componentrefs. As one of the design decision is that every + # file is also a component we walk the list of files and create a + # reference. + for f in files: + ComponentRef = factory.createElement('ComponentRef') + ComponentRef.attributes['Id'] = convert_to_id( os.path.basename(f.get_path()), id_set ) + SubFeature.childNodes.append(ComponentRef) + + Feature.childNodes.append(SubFeature) + + root.getElementsByTagName('Product')[0].childNodes.append(Feature) + +def build_wxsfile_default_gui(root): + """ This function adds a default GUI to the wxs file + """ + factory = Document() + Product = root.getElementsByTagName('Product')[0] + + UIRef = factory.createElement('UIRef') + UIRef.attributes['Id'] = 'WixUI_Mondo' + Product.childNodes.append(UIRef) + + UIRef = factory.createElement('UIRef') + UIRef.attributes['Id'] = 'WixUI_ErrorProgressText' + Product.childNodes.append(UIRef) + +def build_license_file(directory, spec): + """ Creates a License.rtf file with the content of "X_MSI_LICENSE_TEXT" + in the given directory + """ + name, text = '', '' + + try: + name = spec['LICENSE'] + text = spec['X_MSI_LICENSE_TEXT'] + except KeyError: + pass # ignore this as X_MSI_LICENSE_TEXT is optional + + if name!='' or text!='': + file = open( os.path.join(directory.get_path(), 'License.rtf'), 'w' ) + file.write('{\\rtf') + if text!='': + file.write(text.replace('\n', '\\par ')) + else: + file.write(name+'\\par\\par') + file.write('}') + file.close() + +# +# mandatory and optional package tags +# +def build_wxsfile_header_section(root, spec): + """ Adds the xml file node which define the package meta-data. + """ + # Create the needed DOM nodes and add them at the correct position in the tree. + factory = Document() + Product = factory.createElement( 'Product' ) + Package = factory.createElement( 'Package' ) + + root.childNodes.append( Product ) + Product.childNodes.append( Package ) + + # set "mandatory" default values + if 'X_MSI_LANGUAGE' not in spec: + spec['X_MSI_LANGUAGE'] = '1033' # select english + + # mandatory sections, will throw a KeyError if the tag is not available + Product.attributes['Name'] = escape( spec['NAME'] ) + Product.attributes['Version'] = escape( spec['VERSION'] ) + Product.attributes['Manufacturer'] = escape( spec['VENDOR'] ) + Product.attributes['Language'] = escape( spec['X_MSI_LANGUAGE'] ) + Package.attributes['Description'] = escape( spec['SUMMARY'] ) + + # now the optional tags, for which we avoid the KeyErrror exception + if 'DESCRIPTION' in spec: + Package.attributes['Comments'] = escape( spec['DESCRIPTION'] ) + + if 'X_MSI_UPGRADE_CODE' in spec: + Package.attributes['X_MSI_UPGRADE_CODE'] = escape( spec['X_MSI_UPGRADE_CODE'] ) + + # We hardcode the media tag as our current model cannot handle it. + Media = factory.createElement('Media') + Media.attributes['Id'] = '1' + Media.attributes['Cabinet'] = 'default.cab' + Media.attributes['EmbedCab'] = 'yes' + root.getElementsByTagName('Product')[0].childNodes.append(Media) + +# this builder is the entry-point for .wxs file compiler. +wxs_builder = Builder( + action = Action( build_wxsfile, string_wxsfile ), + ensure_suffix = '.wxs' ) + +def package(env, target, source, PACKAGEROOT, NAME, VERSION, + DESCRIPTION, SUMMARY, VENDOR, X_MSI_LANGUAGE, **kw): + # make sure that the Wix Builder is in the environment + SCons.Tool.Tool('wix').generate(env) + + # get put the keywords for the specfile compiler. These are the arguments + # given to the package function and all optional ones stored in kw, minus + # the the source, target and env one. + loc = locals() + del loc['kw'] + kw.update(loc) + del kw['source'], kw['target'], kw['env'] + + # strip the install builder from the source files + target, source = stripinstallbuilder(target, source, env) + + # put the arguments into the env and call the specfile builder. + env['msi_spec'] = kw + specfile = wxs_builder(* [env, target, source], **kw) + + # now call the WiX Tool with the built specfile added as a source. + msifile = env.WiX(target, specfile) + + # return the target and source tuple. + return (msifile, source+[specfile]) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/rpm.py b/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/rpm.py new file mode 100755 index 0000000000..3f44d8354c --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/rpm.py @@ -0,0 +1,362 @@ +"""SCons.Tool.Packaging.rpm + +The rpm packager. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +__revision__ = "src/engine/SCons/Tool/packaging/rpm.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os + +import SCons.Builder +import SCons.Tool.rpmutils + +from SCons.Environment import OverrideEnvironment +from SCons.Tool.packaging import stripinstallbuilder, src_targz +from SCons.Errors import UserError + +def package(env, target, source, PACKAGEROOT, NAME, VERSION, + PACKAGEVERSION, DESCRIPTION, SUMMARY, X_RPM_GROUP, LICENSE, + **kw): + # initialize the rpm tool + SCons.Tool.Tool('rpm').generate(env) + + bld = env['BUILDERS']['Rpm'] + + # Generate a UserError whenever the target name has been set explicitly, + # since rpm does not allow for controlling it. This is detected by + # checking if the target has been set to the default by the Package() + # Environment function. + if str(target[0])!="%s-%s"%(NAME, VERSION): + raise UserError( "Setting target is not supported for rpm." ) + else: + # Deduce the build architecture, but allow it to be overridden + # by setting ARCHITECTURE in the construction env. + buildarchitecture = SCons.Tool.rpmutils.defaultMachine() + if 'ARCHITECTURE' in kw: + buildarchitecture = kw['ARCHITECTURE'] + + fmt = '%s-%s-%s.%s.rpm' + srcrpm = fmt % (NAME, VERSION, PACKAGEVERSION, 'src') + binrpm = fmt % (NAME, VERSION, PACKAGEVERSION, buildarchitecture) + + target = [ srcrpm, binrpm ] + + # get the correct arguments into the kw hash + loc=locals() + del loc['kw'] + kw.update(loc) + del kw['source'], kw['target'], kw['env'] + + # if no "SOURCE_URL" tag is given add a default one. + if 'SOURCE_URL' not in kw: + kw['SOURCE_URL']=(str(target[0])+".tar.gz").replace('.rpm', '') + + # mangle the source and target list for the rpmbuild + env = OverrideEnvironment(env, kw) + target, source = stripinstallbuilder(target, source, env) + target, source = addspecfile(target, source, env) + target, source = collectintargz(target, source, env) + + # now call the rpm builder to actually build the packet. + return bld(env, target, source, **kw) + +def collectintargz(target, source, env): + """ Puts all source files into a tar.gz file. """ + # the rpm tool depends on a source package, until this is changed + # this hack needs to be here that tries to pack all sources in. + sources = env.FindSourceFiles() + + # filter out the target we are building the source list for. + sources = [s for s in sources if s not in target] + + # find the .spec file for rpm and add it since it is not necessarily found + # by the FindSourceFiles function. + sources.extend( [s for s in source if str(s).rfind('.spec')!=-1] ) + # sort to keep sources from changing order across builds + sources.sort() + + # as the source contains the url of the source package this rpm package + # is built from, we extract the target name + tarball = (str(target[0])+".tar.gz").replace('.rpm', '') + try: + tarball = env['SOURCE_URL'].split('/')[-1] + except KeyError as e: + raise SCons.Errors.UserError( "Missing PackageTag '%s' for RPM packager" % e.args[0] ) + + tarball = src_targz.package(env, source=sources, target=tarball, + PACKAGEROOT=env['PACKAGEROOT'], ) + + return (target, tarball) + +def addspecfile(target, source, env): + specfile = "%s-%s" % (env['NAME'], env['VERSION']) + + bld = SCons.Builder.Builder(action = build_specfile, + suffix = '.spec', + target_factory = SCons.Node.FS.File) + + source.extend(bld(env, specfile, source)) + + return (target,source) + +def build_specfile(target, source, env): + """ Builds a RPM specfile from a dictionary with string metadata and + by analyzing a tree of nodes. + """ + with open(target[0].get_abspath(), 'w') as file: + try: + file.write(build_specfile_header(env)) + file.write(build_specfile_sections(env)) + file.write(build_specfile_filesection(env, source)) + + # call a user specified function + if 'CHANGE_SPECFILE' in env: + env['CHANGE_SPECFILE'](target, source) + + except KeyError as e: + raise SCons.Errors.UserError('"%s" package field for RPM is missing.' % e.args[0]) + + +# +# mandatory and optional package tag section +# +def build_specfile_sections(spec): + """ Builds the sections of a rpm specfile. + """ + str = "" + + mandatory_sections = { + 'DESCRIPTION' : '\n%%description\n%s\n\n', } + + str = str + SimpleTagCompiler(mandatory_sections).compile( spec ) + + optional_sections = { + 'DESCRIPTION_' : '%%description -l %s\n%s\n\n', + 'CHANGELOG' : '%%changelog\n%s\n\n', + 'X_RPM_PREINSTALL' : '%%pre\n%s\n\n', + 'X_RPM_POSTINSTALL' : '%%post\n%s\n\n', + 'X_RPM_PREUNINSTALL' : '%%preun\n%s\n\n', + 'X_RPM_POSTUNINSTALL' : '%%postun\n%s\n\n', + 'X_RPM_VERIFY' : '%%verify\n%s\n\n', + + # These are for internal use but could possibly be overridden + 'X_RPM_PREP' : '%%prep\n%s\n\n', + 'X_RPM_BUILD' : '%%build\n%s\n\n', + 'X_RPM_INSTALL' : '%%install\n%s\n\n', + 'X_RPM_CLEAN' : '%%clean\n%s\n\n', + } + + # Default prep, build, install and clean rules + # TODO: optimize those build steps, to not compile the project a second time + if 'X_RPM_PREP' not in spec: + spec['X_RPM_PREP'] = '[ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT"' + '\n%setup -q' + + if 'X_RPM_BUILD' not in spec: + spec['X_RPM_BUILD'] = '[ ! -e "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && mkdir "$RPM_BUILD_ROOT"' + + if 'X_RPM_INSTALL' not in spec: + spec['X_RPM_INSTALL'] = 'scons --install-sandbox="$RPM_BUILD_ROOT" "$RPM_BUILD_ROOT"' + + if 'X_RPM_CLEAN' not in spec: + spec['X_RPM_CLEAN'] = '[ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT"' + + str = str + SimpleTagCompiler(optional_sections, mandatory=0).compile( spec ) + + return str + +def build_specfile_header(spec): + """ Builds all sections but the %file of a rpm specfile + """ + str = "" + + # first the mandatory sections + mandatory_header_fields = { + 'NAME' : '%%define name %s\nName: %%{name}\n', + 'VERSION' : '%%define version %s\nVersion: %%{version}\n', + 'PACKAGEVERSION' : '%%define release %s\nRelease: %%{release}\n', + 'X_RPM_GROUP' : 'Group: %s\n', + 'SUMMARY' : 'Summary: %s\n', + 'LICENSE' : 'License: %s\n', + } + + str = str + SimpleTagCompiler(mandatory_header_fields).compile( spec ) + + # now the optional tags + optional_header_fields = { + 'VENDOR' : 'Vendor: %s\n', + 'X_RPM_URL' : 'Url: %s\n', + 'SOURCE_URL' : 'Source: %s\n', + 'SUMMARY_' : 'Summary(%s): %s\n', + 'ARCHITECTURE' : 'BuildArch: %s\n', + 'X_RPM_DISTRIBUTION' : 'Distribution: %s\n', + 'X_RPM_ICON' : 'Icon: %s\n', + 'X_RPM_PACKAGER' : 'Packager: %s\n', + 'X_RPM_GROUP_' : 'Group(%s): %s\n', + + 'X_RPM_REQUIRES' : 'Requires: %s\n', + 'X_RPM_PROVIDES' : 'Provides: %s\n', + 'X_RPM_CONFLICTS' : 'Conflicts: %s\n', + 'X_RPM_BUILDREQUIRES' : 'BuildRequires: %s\n', + + 'X_RPM_SERIAL' : 'Serial: %s\n', + 'X_RPM_EPOCH' : 'Epoch: %s\n', + 'X_RPM_AUTOREQPROV' : 'AutoReqProv: %s\n', + 'X_RPM_EXCLUDEARCH' : 'ExcludeArch: %s\n', + 'X_RPM_EXCLUSIVEARCH' : 'ExclusiveArch: %s\n', + 'X_RPM_PREFIX' : 'Prefix: %s\n', + + # internal use + 'X_RPM_BUILDROOT' : 'BuildRoot: %s\n', + } + + # fill in default values: + # Adding a BuildRequires renders the .rpm unbuildable under systems which + # are not managed by rpm, since the database to resolve this dependency is + # missing (take Gentoo as an example) + #if 'X_RPM_BUILDREQUIRES' not in spec: + # spec['X_RPM_BUILDREQUIRES'] = 'scons' + + if 'X_RPM_BUILDROOT' not in spec: + spec['X_RPM_BUILDROOT'] = '%{_tmppath}/%{name}-%{version}-%{release}' + + str = str + SimpleTagCompiler(optional_header_fields, mandatory=0).compile( spec ) + + # Add any extra specfile definitions the user may have supplied. + # These flags get no processing, they are just added. + # github #3164: if we don't turn off debug package generation + # the tests which build packages all fail. If there are no + # extra flags, default to adding this one. If the user wants + # to turn this back on, supply the flag set to None. + + if 'X_RPM_EXTRADEFS' not in spec: + spec['X_RPM_EXTRADEFS'] = ['%global debug_package %{nil}'] + for extra in spec['X_RPM_EXTRADEFS']: + str += extra + '\n' + + return str + +# +# mandatory and optional file tags +# +def build_specfile_filesection(spec, files): + """ builds the %file section of the specfile + """ + str = '%files\n' + + if 'X_RPM_DEFATTR' not in spec: + spec['X_RPM_DEFATTR'] = '(-,root,root)' + + str = str + '%%defattr %s\n' % spec['X_RPM_DEFATTR'] + + supported_tags = { + 'PACKAGING_CONFIG' : '%%config %s', + 'PACKAGING_CONFIG_NOREPLACE' : '%%config(noreplace) %s', + 'PACKAGING_DOC' : '%%doc %s', + 'PACKAGING_UNIX_ATTR' : '%%attr %s', + 'PACKAGING_LANG_' : '%%lang(%s) %s', + 'PACKAGING_X_RPM_VERIFY' : '%%verify %s', + 'PACKAGING_X_RPM_DIR' : '%%dir %s', + 'PACKAGING_X_RPM_DOCDIR' : '%%docdir %s', + 'PACKAGING_X_RPM_GHOST' : '%%ghost %s', } + + for file in files: + # build the tagset + tags = {} + for k in list(supported_tags.keys()): + try: + v = file.GetTag(k) + if v: + tags[k] = v + except AttributeError: + pass + + # compile the tagset + str = str + SimpleTagCompiler(supported_tags, mandatory=0).compile( tags ) + + str = str + ' ' + str = str + file.GetTag('PACKAGING_INSTALL_LOCATION') + str = str + '\n\n' + + return str + +class SimpleTagCompiler(object): + """ This class is a simple string substition utility: + the replacement specfication is stored in the tagset dictionary, something + like: + { "abc" : "cdef %s ", + "abc_" : "cdef %s %s" } + + the compile function gets a value dictionary, which may look like: + { "abc" : "ghij", + "abc_gh" : "ij" } + + The resulting string will be: + "cdef ghij cdef gh ij" + """ + def __init__(self, tagset, mandatory=1): + self.tagset = tagset + self.mandatory = mandatory + + def compile(self, values): + """ Compiles the tagset and returns a str containing the result + """ + def is_international(tag): + return tag.endswith('_') + + def get_country_code(tag): + return tag[-2:] + + def strip_country_code(tag): + return tag[:-2] + + replacements = list(self.tagset.items()) + + str = "" + domestic = [t for t in replacements if not is_international(t[0])] + for key, replacement in domestic: + try: + str = str + replacement % values[key] + except KeyError as e: + if self.mandatory: + raise e + + international = [t for t in replacements if is_international(t[0])] + for key, replacement in international: + try: + x = [t for t in values.items() if strip_country_code(t[0]) == key] + int_values_for_key = [(get_country_code(t[0]),t[1]) for t in x] + for v in int_values_for_key: + str = str + replacement % v + except KeyError as e: + if self.mandatory: + raise e + + return str + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/src_tarbz2.py b/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/src_tarbz2.py new file mode 100755 index 0000000000..eea29cb4e7 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/src_tarbz2.py @@ -0,0 +1,43 @@ +"""SCons.Tool.Packaging.src_tarbz2 + +The tarbz2 SRC packager. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/packaging/src_tarbz2.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +from SCons.Tool.packaging import putintopackageroot + +def package(env, target, source, PACKAGEROOT, **kw): + bld = env['BUILDERS']['Tar'] + bld.set_suffix('.tar.bz2') + target, source = putintopackageroot(target, source, env, PACKAGEROOT, honor_install_location=0) + return bld(env, target, source, TARFLAGS='-jc') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/src_targz.py b/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/src_targz.py new file mode 100755 index 0000000000..94ebea43f0 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/src_targz.py @@ -0,0 +1,43 @@ +"""SCons.Tool.Packaging.src_targz + +The targz SRC packager. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/packaging/src_targz.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +from SCons.Tool.packaging import putintopackageroot + +def package(env, target, source, PACKAGEROOT, **kw): + bld = env['BUILDERS']['Tar'] + bld.set_suffix('.tar.gz') + target, source = putintopackageroot(target, source, env, PACKAGEROOT, honor_install_location=0) + return bld(env, target, source, TARFLAGS='-zc') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/src_tarxz.py b/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/src_tarxz.py new file mode 100755 index 0000000000..62db2e2cef --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/src_tarxz.py @@ -0,0 +1,43 @@ +"""SCons.Tool.Packaging.src_tarxz + +The tarxz SRC packager. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/packaging/src_tarxz.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +from SCons.Tool.packaging import putintopackageroot + +def package(env, target, source, PACKAGEROOT, **kw): + bld = env['BUILDERS']['Tar'] + bld.set_suffix('.tar.xz') + target, source = putintopackageroot(target, source, env, PACKAGEROOT, honor_install_location=0) + return bld(env, target, source, TARFLAGS='-Jc') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/src_zip.py b/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/src_zip.py new file mode 100755 index 0000000000..b1f63fbff1 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/src_zip.py @@ -0,0 +1,43 @@ +"""SCons.Tool.Packaging.zip + +The zip SRC packager. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/packaging/src_zip.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +from SCons.Tool.packaging import putintopackageroot + +def package(env, target, source, PACKAGEROOT, **kw): + bld = env['BUILDERS']['Zip'] + bld.set_suffix('.zip') + target, source = putintopackageroot(target, source, env, PACKAGEROOT, honor_install_location=0) + return bld(env, target, source) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/tarbz2.py b/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/tarbz2.py new file mode 100755 index 0000000000..70e7ee43e8 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/tarbz2.py @@ -0,0 +1,44 @@ +"""SCons.Tool.Packaging.tarbz2 + +The tarbz2 packager. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/packaging/tarbz2.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +from SCons.Tool.packaging import stripinstallbuilder, putintopackageroot + +def package(env, target, source, PACKAGEROOT, **kw): + bld = env['BUILDERS']['Tar'] + bld.set_suffix('.tar.bz2') + target, source = putintopackageroot(target, source, env, PACKAGEROOT) + target, source = stripinstallbuilder(target, source, env) + return bld(env, target, source, TARFLAGS='-jc') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/targz.py b/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/targz.py new file mode 100755 index 0000000000..fa8800d55d --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/targz.py @@ -0,0 +1,44 @@ +"""SCons.Tool.Packaging.targz + +The targz packager. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/packaging/targz.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +from SCons.Tool.packaging import stripinstallbuilder, putintopackageroot + +def package(env, target, source, PACKAGEROOT, **kw): + bld = env['BUILDERS']['Tar'] + bld.set_suffix('.tar.gz') + target, source = stripinstallbuilder(target, source, env) + target, source = putintopackageroot(target, source, env, PACKAGEROOT) + return bld(env, target, source, TARFLAGS='-zc') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/tarxz.py b/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/tarxz.py new file mode 100755 index 0000000000..bad495b756 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/tarxz.py @@ -0,0 +1,44 @@ +"""SCons.Tool.Packaging.tarxz + +The tarxz packager. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/packaging/tarxz.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +from SCons.Tool.packaging import stripinstallbuilder, putintopackageroot + +def package(env, target, source, PACKAGEROOT, **kw): + bld = env['BUILDERS']['Tar'] + bld.set_suffix('.tar.xz') + target, source = putintopackageroot(target, source, env, PACKAGEROOT) + target, source = stripinstallbuilder(target, source, env) + return bld(env, target, source, TARFLAGS='-Jc') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/zip.py b/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/zip.py new file mode 100755 index 0000000000..c5dd7ccddd --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/packaging/zip.py @@ -0,0 +1,44 @@ +"""SCons.Tool.Packaging.zip + +The zip SRC packager. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/packaging/zip.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +from SCons.Tool.packaging import stripinstallbuilder, putintopackageroot + +def package(env, target, source, PACKAGEROOT, **kw): + bld = env['BUILDERS']['Zip'] + bld.set_suffix('.zip') + target, source = stripinstallbuilder(target, source, env) + target, source = putintopackageroot(target, source, env, PACKAGEROOT) + return bld(env, target, source) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/pdf.py b/tools/scons/scons-local-3.0.5/SCons/Tool/pdf.py new file mode 100755 index 0000000000..792c4caf01 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/pdf.py @@ -0,0 +1,78 @@ +"""SCons.Tool.pdf + +Common PDF Builder definition for various other Tool modules that use it. +Add an explicit action to run epstopdf to convert .eps files to .pdf + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/pdf.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Builder +import SCons.Tool + +PDFBuilder = None + +EpsPdfAction = SCons.Action.Action('$EPSTOPDFCOM', '$EPSTOPDFCOMSTR') + +def generate(env): + try: + env['BUILDERS']['PDF'] + except KeyError: + global PDFBuilder + if PDFBuilder is None: + PDFBuilder = SCons.Builder.Builder(action = {}, + source_scanner = SCons.Tool.PDFLaTeXScanner, + prefix = '$PDFPREFIX', + suffix = '$PDFSUFFIX', + emitter = {}, + source_ext_match = None, + single_source=True) + env['BUILDERS']['PDF'] = PDFBuilder + + env['PDFPREFIX'] = '' + env['PDFSUFFIX'] = '.pdf' + +# put the epstopdf builder in this routine so we can add it after +# the pdftex builder so that one is the default for no source suffix +def generate2(env): + bld = env['BUILDERS']['PDF'] + #bld.add_action('.ps', EpsPdfAction) # this is covered by direct Ghostcript action in gs.py + bld.add_action('.eps', EpsPdfAction) + + env['EPSTOPDF'] = 'epstopdf' + env['EPSTOPDFFLAGS'] = SCons.Util.CLVar('') + env['EPSTOPDFCOM'] = '$EPSTOPDF $EPSTOPDFFLAGS ${SOURCE} --outfile=${TARGET}' + +def exists(env): + # This only puts a skeleton Builder in place, so if someone + # references this Tool directly, it's always "available." + return 1 + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/pdflatex.py b/tools/scons/scons-local-3.0.5/SCons/Tool/pdflatex.py new file mode 100755 index 0000000000..8d4a1a725d --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/pdflatex.py @@ -0,0 +1,84 @@ +"""SCons.Tool.pdflatex + +Tool-specific initialization for pdflatex. +Generates .pdf files from .latex or .ltx files + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/pdflatex.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Action +import SCons.Util +import SCons.Tool.pdf +import SCons.Tool.tex + +PDFLaTeXAction = None + +def PDFLaTeXAuxFunction(target = None, source= None, env=None): + result = SCons.Tool.tex.InternalLaTeXAuxAction( PDFLaTeXAction, target, source, env ) + if result != 0: + SCons.Tool.tex.check_file_error_message(env['PDFLATEX']) + return result + +PDFLaTeXAuxAction = None + +def generate(env): + """Add Builders and construction variables for pdflatex to an Environment.""" + global PDFLaTeXAction + if PDFLaTeXAction is None: + PDFLaTeXAction = SCons.Action.Action('$PDFLATEXCOM', '$PDFLATEXCOMSTR') + + global PDFLaTeXAuxAction + if PDFLaTeXAuxAction is None: + PDFLaTeXAuxAction = SCons.Action.Action(PDFLaTeXAuxFunction, + strfunction=SCons.Tool.tex.TeXLaTeXStrFunction) + + env.AppendUnique(LATEXSUFFIXES=SCons.Tool.LaTeXSuffixes) + + from . import pdf + pdf.generate(env) + + bld = env['BUILDERS']['PDF'] + bld.add_action('.ltx', PDFLaTeXAuxAction) + bld.add_action('.latex', PDFLaTeXAuxAction) + bld.add_emitter('.ltx', SCons.Tool.tex.tex_pdf_emitter) + bld.add_emitter('.latex', SCons.Tool.tex.tex_pdf_emitter) + + SCons.Tool.tex.generate_common(env) + +def exists(env): + SCons.Tool.tex.generate_darwin(env) + return env.Detect('pdflatex') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/pdftex.py b/tools/scons/scons-local-3.0.5/SCons/Tool/pdftex.py new file mode 100755 index 0000000000..c30066dad8 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/pdftex.py @@ -0,0 +1,109 @@ +"""SCons.Tool.pdftex + +Tool-specific initialization for pdftex. +Generates .pdf files from .tex files + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/pdftex.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os +import SCons.Action +import SCons.Util +import SCons.Tool.tex + +PDFTeXAction = None + +# This action might be needed more than once if we are dealing with +# labels and bibtex. +PDFLaTeXAction = None + +def PDFLaTeXAuxAction(target = None, source= None, env=None): + result = SCons.Tool.tex.InternalLaTeXAuxAction( PDFLaTeXAction, target, source, env ) + return result + +def PDFTeXLaTeXFunction(target = None, source= None, env=None): + """A builder for TeX and LaTeX that scans the source file to + decide the "flavor" of the source and then executes the appropriate + program.""" + basedir = os.path.split(str(source[0]))[0] + abspath = os.path.abspath(basedir) + + if SCons.Tool.tex.is_LaTeX(source,env,abspath): + result = PDFLaTeXAuxAction(target,source,env) + if result != 0: + SCons.Tool.tex.check_file_error_message(env['PDFLATEX']) + else: + result = PDFTeXAction(target,source,env) + if result != 0: + SCons.Tool.tex.check_file_error_message(env['PDFTEX']) + return result + +PDFTeXLaTeXAction = None + +def generate(env): + """Add Builders and construction variables for pdftex to an Environment.""" + global PDFTeXAction + if PDFTeXAction is None: + PDFTeXAction = SCons.Action.Action('$PDFTEXCOM', '$PDFTEXCOMSTR') + + global PDFLaTeXAction + if PDFLaTeXAction is None: + PDFLaTeXAction = SCons.Action.Action("$PDFLATEXCOM", "$PDFLATEXCOMSTR") + + global PDFTeXLaTeXAction + if PDFTeXLaTeXAction is None: + PDFTeXLaTeXAction = SCons.Action.Action(PDFTeXLaTeXFunction, + strfunction=SCons.Tool.tex.TeXLaTeXStrFunction) + + env.AppendUnique(LATEXSUFFIXES=SCons.Tool.LaTeXSuffixes) + + from . import pdf + pdf.generate(env) + + bld = env['BUILDERS']['PDF'] + bld.add_action('.tex', PDFTeXLaTeXAction) + bld.add_emitter('.tex', SCons.Tool.tex.tex_pdf_emitter) + + # Add the epstopdf builder after the pdftex builder + # so pdftex is the default for no source suffix + pdf.generate2(env) + + SCons.Tool.tex.generate_common(env) + +def exists(env): + SCons.Tool.tex.generate_darwin(env) + return env.Detect('pdftex') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/qt.py b/tools/scons/scons-local-3.0.5/SCons/Tool/qt.py new file mode 100755 index 0000000000..1b1925c6bb --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/qt.py @@ -0,0 +1,367 @@ + +"""SCons.Tool.qt + +Tool-specific initialization for Qt. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +from __future__ import print_function + +__revision__ = "src/engine/SCons/Tool/qt.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os.path +import re +import glob + +import SCons.Action +import SCons.Builder +import SCons.Defaults +import SCons.Scanner +import SCons.Tool +import SCons.Util +import SCons.Tool.cxx +cplusplus = SCons.Tool.cxx + +class ToolQtWarning(SCons.Warnings.Warning): + pass + +class GeneratedMocFileNotIncluded(ToolQtWarning): + pass + +class QtdirNotFound(ToolQtWarning): + pass + +SCons.Warnings.enableWarningClass(ToolQtWarning) + +header_extensions = [".h", ".hxx", ".hpp", ".hh"] +if SCons.Util.case_sensitive_suffixes('.h', '.H'): + header_extensions.append('.H') + +cxx_suffixes = cplusplus.CXXSuffixes + + +# +def find_platform_specific_qt_paths(): + """ + If the platform has non-standard paths which it installs QT in,return the likely default path + :return: + """ + + # qt_bin_dirs = [] + qt_bin_dir = None + if os.path.isfile('/etc/redhat-release'): + with open('/etc/redhat-release','r') as rr: + lines = rr.readlines() + distro = lines[0].split()[0] + if distro == 'CentOS': + # Centos installs QT under /usr/{lib,lib64}/qt{4,5,-3.3}/bin + # so we need to handle this differently + # qt_bin_dirs = glob.glob('/usr/lib64/qt*/bin') + qt_bin_dir = '/usr/lib64/qt-3.3/bin' + + return qt_bin_dir + + +QT_BIN_DIR = find_platform_specific_qt_paths() + +def checkMocIncluded(target, source, env): + moc = target[0] + cpp = source[0] + # looks like cpp.includes is cleared before the build stage :-( + # not really sure about the path transformations (moc.cwd? cpp.cwd?) :-/ + path = SCons.Defaults.CScan.path(env, moc.cwd) + includes = SCons.Defaults.CScan(cpp, env, path) + if not moc in includes: + SCons.Warnings.warn( + GeneratedMocFileNotIncluded, + "Generated moc file '%s' is not included by '%s'" % + (str(moc), str(cpp))) + +def find_file(filename, paths, node_factory): + for dir in paths: + node = node_factory(filename, dir) + if node.rexists(): + return node + return None + +class _Automoc(object): + """ + Callable class, which works as an emitter for Programs, SharedLibraries and + StaticLibraries. + """ + + def __init__(self, objBuilderName): + self.objBuilderName = objBuilderName + + def __call__(self, target, source, env): + """ + Smart autoscan function. Gets the list of objects for the Program + or Lib. Adds objects and builders for the special qt files. + """ + try: + if int(env.subst('$QT_AUTOSCAN')) == 0: + return target, source + except ValueError: + pass + try: + debug = int(env.subst('$QT_DEBUG')) + except ValueError: + debug = 0 + + # some shortcuts used in the scanner + splitext = SCons.Util.splitext + objBuilder = getattr(env, self.objBuilderName) + + # some regular expressions: + # Q_OBJECT detection + q_object_search = re.compile(r'[^A-Za-z0-9]Q_OBJECT[^A-Za-z0-9]') + # cxx and c comment 'eater' + #comment = re.compile(r'(//.*)|(/\*(([^*])|(\*[^/]))*\*/)') + # CW: something must be wrong with the regexp. See also bug #998222 + # CURRENTLY THERE IS NO TEST CASE FOR THAT + + # The following is kind of hacky to get builders working properly (FIXME) + objBuilderEnv = objBuilder.env + objBuilder.env = env + mocBuilderEnv = env.Moc.env + env.Moc.env = env + + # make a deep copy for the result; MocH objects will be appended + out_sources = source[:] + + for obj in source: + if not obj.has_builder(): + # binary obj file provided + if debug: + print("scons: qt: '%s' seems to be a binary. Discarded." % str(obj)) + continue + cpp = obj.sources[0] + if not splitext(str(cpp))[1] in cxx_suffixes: + if debug: + print("scons: qt: '%s' is no cxx file. Discarded." % str(cpp)) + # c or fortran source + continue + #cpp_contents = comment.sub('', cpp.get_text_contents()) + if debug: + print("scons: qt: Getting contents of %s" % cpp) + cpp_contents = cpp.get_text_contents() + h=None + for h_ext in header_extensions: + # try to find the header file in the corresponding source + # directory + hname = splitext(cpp.name)[0] + h_ext + h = find_file(hname, (cpp.get_dir(),), env.File) + if h: + if debug: + print("scons: qt: Scanning '%s' (header of '%s')" % (str(h), str(cpp))) + #h_contents = comment.sub('', h.get_text_contents()) + h_contents = h.get_text_contents() + break + if not h and debug: + print("scons: qt: no header for '%s'." % (str(cpp))) + if h and q_object_search.search(h_contents): + # h file with the Q_OBJECT macro found -> add moc_cpp + moc_cpp = env.Moc(h) + moc_o = objBuilder(moc_cpp) + out_sources.append(moc_o) + #moc_cpp.target_scanner = SCons.Defaults.CScan + if debug: + print("scons: qt: found Q_OBJECT macro in '%s', moc'ing to '%s'" % (str(h), str(moc_cpp))) + if cpp and q_object_search.search(cpp_contents): + # cpp file with Q_OBJECT macro found -> add moc + # (to be included in cpp) + moc = env.Moc(cpp) + env.Ignore(moc, moc) + if debug: + print("scons: qt: found Q_OBJECT macro in '%s', moc'ing to '%s'" % (str(cpp), str(moc))) + #moc.source_scanner = SCons.Defaults.CScan + # restore the original env attributes (FIXME) + objBuilder.env = objBuilderEnv + env.Moc.env = mocBuilderEnv + + return (target, out_sources) + +AutomocShared = _Automoc('SharedObject') +AutomocStatic = _Automoc('StaticObject') + +def _detect(env): + """Not really safe, but fast method to detect the QT library""" + + QTDIR = env.get('QTDIR',None) + if not QTDIR: + QTDIR = os.environ.get('QTDIR',None) + if not QTDIR: + moc = env.WhereIs('moc') or env.WhereIs('moc',QT_BIN_DIR) + if moc: + QTDIR = os.path.dirname(os.path.dirname(moc)) + SCons.Warnings.warn( + QtdirNotFound, + "Could not detect qt, using moc executable as a hint (QTDIR=%s)" % QTDIR) + else: + QTDIR = None + SCons.Warnings.warn( + QtdirNotFound, + "Could not detect qt, using empty QTDIR") + return QTDIR + +def uicEmitter(target, source, env): + adjustixes = SCons.Util.adjustixes + bs = SCons.Util.splitext(str(source[0].name))[0] + bs = os.path.join(str(target[0].get_dir()),bs) + # first target (header) is automatically added by builder + if len(target) < 2: + # second target is implementation + target.append(adjustixes(bs, + env.subst('$QT_UICIMPLPREFIX'), + env.subst('$QT_UICIMPLSUFFIX'))) + if len(target) < 3: + # third target is moc file + target.append(adjustixes(bs, + env.subst('$QT_MOCHPREFIX'), + env.subst('$QT_MOCHSUFFIX'))) + return target, source + +def uicScannerFunc(node, env, path): + lookout = [] + lookout.extend(env['CPPPATH']) + lookout.append(str(node.rfile().dir)) + includes = re.findall("(.*?)", node.get_text_contents()) + result = [] + for incFile in includes: + dep = env.FindFile(incFile,lookout) + if dep: + result.append(dep) + return result + +uicScanner = SCons.Scanner.Base(uicScannerFunc, + name = "UicScanner", + node_class = SCons.Node.FS.File, + node_factory = SCons.Node.FS.File, + recursive = 0) + +def generate(env): + """Add Builders and construction variables for qt to an Environment.""" + CLVar = SCons.Util.CLVar + Action = SCons.Action.Action + Builder = SCons.Builder.Builder + + env.SetDefault(QTDIR = _detect(env), + QT_BINPATH = os.path.join('$QTDIR', 'bin'), + QT_CPPPATH = os.path.join('$QTDIR', 'include'), + QT_LIBPATH = os.path.join('$QTDIR', 'lib'), + QT_MOC = os.path.join('$QT_BINPATH','moc'), + QT_UIC = os.path.join('$QT_BINPATH','uic'), + QT_LIB = 'qt', # may be set to qt-mt + + QT_AUTOSCAN = 1, # scan for moc'able sources + + # Some QT specific flags. I don't expect someone wants to + # manipulate those ... + QT_UICIMPLFLAGS = CLVar(''), + QT_UICDECLFLAGS = CLVar(''), + QT_MOCFROMHFLAGS = CLVar(''), + QT_MOCFROMCXXFLAGS = CLVar('-i'), + + # suffixes/prefixes for the headers / sources to generate + QT_UICDECLPREFIX = '', + QT_UICDECLSUFFIX = '.h', + QT_UICIMPLPREFIX = 'uic_', + QT_UICIMPLSUFFIX = '$CXXFILESUFFIX', + QT_MOCHPREFIX = 'moc_', + QT_MOCHSUFFIX = '$CXXFILESUFFIX', + QT_MOCCXXPREFIX = '', + QT_MOCCXXSUFFIX = '.moc', + QT_UISUFFIX = '.ui', + + # Commands for the qt support ... + # command to generate header, implementation and moc-file + # from a .ui file + QT_UICCOM = [ + CLVar('$QT_UIC $QT_UICDECLFLAGS -o ${TARGETS[0]} $SOURCE'), + CLVar('$QT_UIC $QT_UICIMPLFLAGS -impl ${TARGETS[0].file} ' + '-o ${TARGETS[1]} $SOURCE'), + CLVar('$QT_MOC $QT_MOCFROMHFLAGS -o ${TARGETS[2]} ${TARGETS[0]}')], + # command to generate meta object information for a class + # declarated in a header + QT_MOCFROMHCOM = ( + '$QT_MOC $QT_MOCFROMHFLAGS -o ${TARGETS[0]} $SOURCE'), + # command to generate meta object information for a class + # declarated in a cpp file + QT_MOCFROMCXXCOM = [ + CLVar('$QT_MOC $QT_MOCFROMCXXFLAGS -o ${TARGETS[0]} $SOURCE'), + Action(checkMocIncluded,None)]) + + # ... and the corresponding builders + uicBld = Builder(action=SCons.Action.Action('$QT_UICCOM', '$QT_UICCOMSTR'), + emitter=uicEmitter, + src_suffix='$QT_UISUFFIX', + suffix='$QT_UICDECLSUFFIX', + prefix='$QT_UICDECLPREFIX', + source_scanner=uicScanner) + mocBld = Builder(action={}, prefix={}, suffix={}) + for h in header_extensions: + act = SCons.Action.Action('$QT_MOCFROMHCOM', '$QT_MOCFROMHCOMSTR') + mocBld.add_action(h, act) + mocBld.prefix[h] = '$QT_MOCHPREFIX' + mocBld.suffix[h] = '$QT_MOCHSUFFIX' + for cxx in cxx_suffixes: + act = SCons.Action.Action('$QT_MOCFROMCXXCOM', '$QT_MOCFROMCXXCOMSTR') + mocBld.add_action(cxx, act) + mocBld.prefix[cxx] = '$QT_MOCCXXPREFIX' + mocBld.suffix[cxx] = '$QT_MOCCXXSUFFIX' + + # register the builders + env['BUILDERS']['Uic'] = uicBld + env['BUILDERS']['Moc'] = mocBld + static_obj, shared_obj = SCons.Tool.createObjBuilders(env) + static_obj.add_src_builder('Uic') + shared_obj.add_src_builder('Uic') + + # We use the emitters of Program / StaticLibrary / SharedLibrary + # to scan for moc'able files + # We can't refer to the builders directly, we have to fetch them + # as Environment attributes because that sets them up to be called + # correctly later by our emitter. + env.AppendUnique(PROGEMITTER =[AutomocStatic], + SHLIBEMITTER=[AutomocShared], + LDMODULEEMITTER=[AutomocShared], + LIBEMITTER =[AutomocStatic], + # Of course, we need to link against the qt libraries + CPPPATH=["$QT_CPPPATH"], + LIBPATH=["$QT_LIBPATH"], + LIBS=['$QT_LIB']) + +def exists(env): + return _detect(env) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/rmic.py b/tools/scons/scons-local-3.0.5/SCons/Tool/rmic.py new file mode 100755 index 0000000000..b2df405992 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/rmic.py @@ -0,0 +1,141 @@ +"""SCons.Tool.rmic + +Tool-specific initialization for rmic. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/rmic.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os.path + +import SCons.Action +import SCons.Builder +import SCons.Node.FS +import SCons.Util + +from SCons.Tool.JavaCommon import get_java_install_dirs + + +def emit_rmic_classes(target, source, env): + """Create and return lists of Java RMI stub and skeleton + class files to be created from a set of class files. + """ + class_suffix = env.get('JAVACLASSSUFFIX', '.class') + classdir = env.get('JAVACLASSDIR') + + if not classdir: + try: + s = source[0] + except IndexError: + classdir = '.' + else: + try: + classdir = s.attributes.java_classdir + except AttributeError: + classdir = '.' + classdir = env.Dir(classdir).rdir() + if str(classdir) == '.': + c_ = None + else: + c_ = str(classdir) + os.sep + + slist = [] + for src in source: + try: + classname = src.attributes.java_classname + except AttributeError: + classname = str(src) + if c_ and classname[:len(c_)] == c_: + classname = classname[len(c_):] + if class_suffix and classname[:-len(class_suffix)] == class_suffix: + classname = classname[-len(class_suffix):] + s = src.rfile() + s.attributes.java_classdir = classdir + s.attributes.java_classname = classname + slist.append(s) + + stub_suffixes = ['_Stub'] + if env.get('JAVAVERSION') == '1.4': + stub_suffixes.append('_Skel') + + tlist = [] + for s in source: + for suff in stub_suffixes: + fname = s.attributes.java_classname.replace('.', os.sep) + \ + suff + class_suffix + t = target[0].File(fname) + t.attributes.java_lookupdir = target[0] + tlist.append(t) + + return tlist, source + +RMICAction = SCons.Action.Action('$RMICCOM', '$RMICCOMSTR') + +RMICBuilder = SCons.Builder.Builder(action = RMICAction, + emitter = emit_rmic_classes, + src_suffix = '$JAVACLASSSUFFIX', + target_factory = SCons.Node.FS.Dir, + source_factory = SCons.Node.FS.File) + +def generate(env): + """Add Builders and construction variables for rmic to an Environment.""" + env['BUILDERS']['RMIC'] = RMICBuilder + + if env['PLATFORM'] == 'win32': + version = env.get('JAVAVERSION', None) + default_paths=get_java_install_dirs(env['PLATFORM'], version=version) + + # Ensure that we have a proper path for rmic + rmic = SCons.Tool.find_program_path(env, 'rmic', default_paths=default_paths) + + # print("RMIC: %s"%rmic) + if rmic: + rmic_bin_dir = os.path.dirname(rmic) + env.AppendENVPath('PATH', rmic_bin_dir) + + env['RMIC'] = 'rmic' + env['RMICFLAGS'] = SCons.Util.CLVar('') + env['RMICCOM'] = '$RMIC $RMICFLAGS -d ${TARGET.attributes.java_lookupdir} -classpath ${SOURCE.attributes.java_classdir} ${SOURCES.attributes.java_classname}' + env['JAVACLASSSUFFIX'] = '.class' + +def exists(env): + # As reported by Jan Nijtmans in issue #2730, the simple + # return env.Detect('rmic') + # doesn't always work during initialization. For now, we + # stop trying to detect an executable (analogous to the + # javac Builder). + # TODO: Come up with a proper detect() routine...and enable it. + return 1 + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/rpcgen.py b/tools/scons/scons-local-3.0.5/SCons/Tool/rpcgen.py new file mode 100755 index 0000000000..a495fdd122 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/rpcgen.py @@ -0,0 +1,70 @@ +"""SCons.Tool.rpcgen + +Tool-specific initialization for RPCGEN tools. + +Three normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/rpcgen.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +from SCons.Builder import Builder +import SCons.Util + +cmd = "cd ${SOURCE.dir} && $RPCGEN -%s $RPCGENFLAGS %s -o ${TARGET.abspath} ${SOURCE.file}" + +rpcgen_client = cmd % ('l', '$RPCGENCLIENTFLAGS') +rpcgen_header = cmd % ('h', '$RPCGENHEADERFLAGS') +rpcgen_service = cmd % ('m', '$RPCGENSERVICEFLAGS') +rpcgen_xdr = cmd % ('c', '$RPCGENXDRFLAGS') + +def generate(env): + """Add RPCGEN Builders and construction variables for an Environment.""" + + client = Builder(action=rpcgen_client, suffix='_clnt.c', src_suffix='.x') + header = Builder(action=rpcgen_header, suffix='.h', src_suffix='.x') + service = Builder(action=rpcgen_service, suffix='_svc.c', src_suffix='.x') + xdr = Builder(action=rpcgen_xdr, suffix='_xdr.c', src_suffix='.x') + env.Append(BUILDERS={'RPCGenClient' : client, + 'RPCGenHeader' : header, + 'RPCGenService' : service, + 'RPCGenXDR' : xdr}) + env['RPCGEN'] = 'rpcgen' + env['RPCGENFLAGS'] = SCons.Util.CLVar('') + env['RPCGENCLIENTFLAGS'] = SCons.Util.CLVar('') + env['RPCGENHEADERFLAGS'] = SCons.Util.CLVar('') + env['RPCGENSERVICEFLAGS'] = SCons.Util.CLVar('') + env['RPCGENXDRFLAGS'] = SCons.Util.CLVar('') + +def exists(env): + return env.Detect('rpcgen') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/rpm.py b/tools/scons/scons-local-3.0.5/SCons/Tool/rpm.py new file mode 100755 index 0000000000..9531431521 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/rpm.py @@ -0,0 +1,132 @@ +"""SCons.Tool.rpm + +Tool-specific initialization for rpm. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +The rpm tool calls the rpmbuild command. The first and only argument should a +tar.gz consisting of the source file and a specfile. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/rpm.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os +import re +import shutil +import subprocess + +import SCons.Builder +import SCons.Node.FS +import SCons.Util +import SCons.Action +import SCons.Defaults + +def get_cmd(source, env): + tar_file_with_included_specfile = source + if SCons.Util.is_List(source): + tar_file_with_included_specfile = source[0] + return "%s %s %s"%(env['RPM'], env['RPMFLAGS'], + tar_file_with_included_specfile.get_abspath() ) + +def build_rpm(target, source, env): + # create a temporary rpm build root. + tmpdir = os.path.join( os.path.dirname( target[0].get_abspath() ), 'rpmtemp' ) + if os.path.exists(tmpdir): + shutil.rmtree(tmpdir) + + # now create the mandatory rpm directory structure. + for d in ['RPMS', 'SRPMS', 'SPECS', 'BUILD']: + os.makedirs( os.path.join( tmpdir, d ) ) + + # set the topdir as an rpmflag. + env.Prepend( RPMFLAGS = '--define \'_topdir %s\'' % tmpdir ) + + # now call rpmbuild to create the rpm package. + handle = subprocess.Popen(get_cmd(source, env), + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + shell=True) + output = SCons.Util.to_str(handle.stdout.read()) + status = handle.wait() + + if status: + raise SCons.Errors.BuildError( node=target[0], + errstr=output, + filename=str(target[0]) ) + else: + # XXX: assume that LC_ALL=C is set while running rpmbuild + output_files = re.compile( 'Wrote: (.*)' ).findall( output ) + + for output, input in zip( output_files, target ): + rpm_output = os.path.basename(output) + expected = os.path.basename(input.get_path()) + + assert expected == rpm_output, "got %s but expected %s" % (rpm_output, expected) + shutil.copy( output, input.get_abspath() ) + + + # cleanup before leaving. + shutil.rmtree(tmpdir) + + return status + +def string_rpm(target, source, env): + try: + return env['RPMCOMSTR'] + except KeyError: + return get_cmd(source, env) + +rpmAction = SCons.Action.Action(build_rpm, string_rpm) + +RpmBuilder = SCons.Builder.Builder(action = SCons.Action.Action('$RPMCOM', '$RPMCOMSTR'), + source_scanner = SCons.Defaults.DirScanner, + suffix = '$RPMSUFFIX') + + + +def generate(env): + """Add Builders and construction variables for rpm to an Environment.""" + try: + bld = env['BUILDERS']['Rpm'] + except KeyError: + bld = RpmBuilder + env['BUILDERS']['Rpm'] = bld + + env.SetDefault(RPM = 'LC_ALL=C rpmbuild') + env.SetDefault(RPMFLAGS = SCons.Util.CLVar('-ta')) + env.SetDefault(RPMCOM = rpmAction) + env.SetDefault(RPMSUFFIX = '.rpm') + +def exists(env): + return env.Detect('rpmbuild') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/rpmutils.py b/tools/scons/scons-local-3.0.5/SCons/Tool/rpmutils.py new file mode 100755 index 0000000000..6c87f73a1c --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/rpmutils.py @@ -0,0 +1,547 @@ +"""SCons.Tool.rpmutils.py + +RPM specific helper routines for general usage in the test framework +and SCons core modules. + +Since we check for the RPM package target name in several places, +we have to know which machine/system name RPM will use for the current +hardware setup. The following dictionaries and functions try to +mimic the exact naming rules of the RPM source code. +They were directly derived from the file "rpmrc.in" of the version +rpm-4.9.1.3. For updating to a more recent version of RPM, this Python +script can be used standalone. The usage() function below shows the +exact syntax. + +""" + +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from __future__ import print_function + +__revision__ = "src/engine/SCons/Tool/rpmutils.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + + +import platform +import subprocess + +import SCons.Util + +# Start of rpmrc dictionaries (Marker, don't change or remove!) +os_canon = { + 'AIX' : ['AIX','5'], + 'AmigaOS' : ['AmigaOS','5'], + 'BSD_OS' : ['bsdi','12'], + 'CYGWIN32_95' : ['cygwin32','15'], + 'CYGWIN32_NT' : ['cygwin32','14'], + 'Darwin' : ['darwin','21'], + 'FreeBSD' : ['FreeBSD','8'], + 'HP-UX' : ['hpux10','6'], + 'IRIX' : ['Irix','2'], + 'IRIX64' : ['Irix64','10'], + 'Linux' : ['Linux','1'], + 'Linux/390' : ['OS/390','20'], + 'Linux/ESA' : ['VM/ESA','20'], + 'MacOSX' : ['macosx','21'], + 'MiNT' : ['FreeMiNT','17'], + 'NEXTSTEP' : ['NextStep','11'], + 'OS/390' : ['OS/390','18'], + 'OSF1' : ['osf1','7'], + 'SCO_SV' : ['SCO_SV3.2v5.0.2','9'], + 'SunOS4' : ['SunOS','4'], + 'SunOS5' : ['solaris','3'], + 'UNIX_SV' : ['MP_RAS','16'], + 'VM/ESA' : ['VM/ESA','19'], + 'machten' : ['machten','13'], + 'osf3.2' : ['osf1','7'], + 'osf4.0' : ['osf1','7'], +} + +buildarch_compat = { + 'alpha' : ['noarch'], + 'alphaev5' : ['alpha'], + 'alphaev56' : ['alphaev5'], + 'alphaev6' : ['alphapca56'], + 'alphaev67' : ['alphaev6'], + 'alphapca56' : ['alphaev56'], + 'amd64' : ['x86_64'], + 'armv3l' : ['noarch'], + 'armv4b' : ['noarch'], + 'armv4l' : ['armv3l'], + 'armv4tl' : ['armv4l'], + 'armv5tejl' : ['armv5tel'], + 'armv5tel' : ['armv4tl'], + 'armv6l' : ['armv5tejl'], + 'armv7l' : ['armv6l'], + 'atariclone' : ['m68kmint','noarch'], + 'atarist' : ['m68kmint','noarch'], + 'atariste' : ['m68kmint','noarch'], + 'ataritt' : ['m68kmint','noarch'], + 'athlon' : ['i686'], + 'falcon' : ['m68kmint','noarch'], + 'geode' : ['i586'], + 'hades' : ['m68kmint','noarch'], + 'hppa1.0' : ['parisc'], + 'hppa1.1' : ['hppa1.0'], + 'hppa1.2' : ['hppa1.1'], + 'hppa2.0' : ['hppa1.2'], + 'i386' : ['noarch','fat'], + 'i486' : ['i386'], + 'i586' : ['i486'], + 'i686' : ['i586'], + 'ia32e' : ['x86_64'], + 'ia64' : ['noarch'], + 'm68k' : ['noarch'], + 'milan' : ['m68kmint','noarch'], + 'mips' : ['noarch'], + 'mipsel' : ['noarch'], + 'parisc' : ['noarch'], + 'pentium3' : ['i686'], + 'pentium4' : ['pentium3'], + 'ppc' : ['noarch','fat'], + 'ppc32dy4' : ['noarch'], + 'ppc64' : ['noarch','fat'], + 'ppc64iseries' : ['ppc64'], + 'ppc64pseries' : ['ppc64'], + 'ppc8260' : ['noarch'], + 'ppc8560' : ['noarch'], + 'ppciseries' : ['noarch'], + 'ppcpseries' : ['noarch'], + 's390' : ['noarch'], + 's390x' : ['noarch'], + 'sh3' : ['noarch'], + 'sh4' : ['noarch'], + 'sh4a' : ['sh4'], + 'sparc' : ['noarch'], + 'sparc64' : ['sparcv9v'], + 'sparc64v' : ['sparc64'], + 'sparcv8' : ['sparc'], + 'sparcv9' : ['sparcv8'], + 'sparcv9v' : ['sparcv9'], + 'sun4c' : ['noarch'], + 'sun4d' : ['noarch'], + 'sun4m' : ['noarch'], + 'sun4u' : ['noarch'], + 'x86_64' : ['noarch'], +} + +os_compat = { + 'BSD_OS' : ['bsdi'], + 'Darwin' : ['MacOSX'], + 'FreeMiNT' : ['mint','MiNT','TOS'], + 'IRIX64' : ['IRIX'], + 'MiNT' : ['FreeMiNT','mint','TOS'], + 'TOS' : ['FreeMiNT','MiNT','mint'], + 'bsdi4.0' : ['bsdi'], + 'hpux10.00' : ['hpux9.07'], + 'hpux10.01' : ['hpux10.00'], + 'hpux10.10' : ['hpux10.01'], + 'hpux10.20' : ['hpux10.10'], + 'hpux10.30' : ['hpux10.20'], + 'hpux11.00' : ['hpux10.30'], + 'hpux9.05' : ['hpux9.04'], + 'hpux9.07' : ['hpux9.05'], + 'mint' : ['FreeMiNT','MiNT','TOS'], + 'ncr-sysv4.3' : ['ncr-sysv4.2'], + 'osf4.0' : ['osf3.2','osf1'], + 'solaris2.4' : ['solaris2.3'], + 'solaris2.5' : ['solaris2.3','solaris2.4'], + 'solaris2.6' : ['solaris2.3','solaris2.4','solaris2.5'], + 'solaris2.7' : ['solaris2.3','solaris2.4','solaris2.5','solaris2.6'], +} + +arch_compat = { + 'alpha' : ['axp','noarch'], + 'alphaev5' : ['alpha'], + 'alphaev56' : ['alphaev5'], + 'alphaev6' : ['alphapca56'], + 'alphaev67' : ['alphaev6'], + 'alphapca56' : ['alphaev56'], + 'amd64' : ['x86_64','athlon','noarch'], + 'armv3l' : ['noarch'], + 'armv4b' : ['noarch'], + 'armv4l' : ['armv3l'], + 'armv4tl' : ['armv4l'], + 'armv5tejl' : ['armv5tel'], + 'armv5tel' : ['armv4tl'], + 'armv6l' : ['armv5tejl'], + 'armv7l' : ['armv6l'], + 'atariclone' : ['m68kmint','noarch'], + 'atarist' : ['m68kmint','noarch'], + 'atariste' : ['m68kmint','noarch'], + 'ataritt' : ['m68kmint','noarch'], + 'athlon' : ['i686'], + 'falcon' : ['m68kmint','noarch'], + 'geode' : ['i586'], + 'hades' : ['m68kmint','noarch'], + 'hppa1.0' : ['parisc'], + 'hppa1.1' : ['hppa1.0'], + 'hppa1.2' : ['hppa1.1'], + 'hppa2.0' : ['hppa1.2'], + 'i370' : ['noarch'], + 'i386' : ['noarch','fat'], + 'i486' : ['i386'], + 'i586' : ['i486'], + 'i686' : ['i586'], + 'ia32e' : ['x86_64','athlon','noarch'], + 'ia64' : ['noarch'], + 'milan' : ['m68kmint','noarch'], + 'mips' : ['noarch'], + 'mipsel' : ['noarch'], + 'osfmach3_i386' : ['i486'], + 'osfmach3_i486' : ['i486','osfmach3_i386'], + 'osfmach3_i586' : ['i586','osfmach3_i486'], + 'osfmach3_i686' : ['i686','osfmach3_i586'], + 'osfmach3_ppc' : ['ppc'], + 'parisc' : ['noarch'], + 'pentium3' : ['i686'], + 'pentium4' : ['pentium3'], + 'powerpc' : ['ppc'], + 'powerppc' : ['ppc'], + 'ppc' : ['rs6000'], + 'ppc32dy4' : ['ppc'], + 'ppc64' : ['ppc'], + 'ppc64iseries' : ['ppc64'], + 'ppc64pseries' : ['ppc64'], + 'ppc8260' : ['ppc'], + 'ppc8560' : ['ppc'], + 'ppciseries' : ['ppc'], + 'ppcpseries' : ['ppc'], + 'rs6000' : ['noarch','fat'], + 's390' : ['noarch'], + 's390x' : ['s390','noarch'], + 'sh3' : ['noarch'], + 'sh4' : ['noarch'], + 'sh4a' : ['sh4'], + 'sparc' : ['noarch'], + 'sparc64' : ['sparcv9'], + 'sparc64v' : ['sparc64'], + 'sparcv8' : ['sparc'], + 'sparcv9' : ['sparcv8'], + 'sparcv9v' : ['sparcv9'], + 'sun4c' : ['sparc'], + 'sun4d' : ['sparc'], + 'sun4m' : ['sparc'], + 'sun4u' : ['sparc64'], + 'x86_64' : ['amd64','athlon','noarch'], +} + +buildarchtranslate = { + 'alphaev5' : ['alpha'], + 'alphaev56' : ['alpha'], + 'alphaev6' : ['alpha'], + 'alphaev67' : ['alpha'], + 'alphapca56' : ['alpha'], + 'amd64' : ['x86_64'], + 'armv3l' : ['armv3l'], + 'armv4b' : ['armv4b'], + 'armv4l' : ['armv4l'], + 'armv4tl' : ['armv4tl'], + 'armv5tejl' : ['armv5tejl'], + 'armv5tel' : ['armv5tel'], + 'armv6l' : ['armv6l'], + 'armv7l' : ['armv7l'], + 'atariclone' : ['m68kmint'], + 'atarist' : ['m68kmint'], + 'atariste' : ['m68kmint'], + 'ataritt' : ['m68kmint'], + 'athlon' : ['i386'], + 'falcon' : ['m68kmint'], + 'geode' : ['i386'], + 'hades' : ['m68kmint'], + 'i386' : ['i386'], + 'i486' : ['i386'], + 'i586' : ['i386'], + 'i686' : ['i386'], + 'ia32e' : ['x86_64'], + 'ia64' : ['ia64'], + 'milan' : ['m68kmint'], + 'osfmach3_i386' : ['i386'], + 'osfmach3_i486' : ['i386'], + 'osfmach3_i586' : ['i386'], + 'osfmach3_i686' : ['i386'], + 'osfmach3_ppc' : ['ppc'], + 'pentium3' : ['i386'], + 'pentium4' : ['i386'], + 'powerpc' : ['ppc'], + 'powerppc' : ['ppc'], + 'ppc32dy4' : ['ppc'], + 'ppc64iseries' : ['ppc64'], + 'ppc64pseries' : ['ppc64'], + 'ppc8260' : ['ppc'], + 'ppc8560' : ['ppc'], + 'ppciseries' : ['ppc'], + 'ppcpseries' : ['ppc'], + 's390' : ['s390'], + 's390x' : ['s390x'], + 'sh3' : ['sh3'], + 'sh4' : ['sh4'], + 'sh4a' : ['sh4'], + 'sparc64v' : ['sparc64'], + 'sparcv8' : ['sparc'], + 'sparcv9' : ['sparc'], + 'sparcv9v' : ['sparc'], + 'sun4c' : ['sparc'], + 'sun4d' : ['sparc'], + 'sun4m' : ['sparc'], + 'sun4u' : ['sparc64'], + 'x86_64' : ['x86_64'], +} + +optflags = { + 'alpha' : ['-O2','-g','-mieee'], + 'alphaev5' : ['-O2','-g','-mieee','-mtune=ev5'], + 'alphaev56' : ['-O2','-g','-mieee','-mtune=ev56'], + 'alphaev6' : ['-O2','-g','-mieee','-mtune=ev6'], + 'alphaev67' : ['-O2','-g','-mieee','-mtune=ev67'], + 'alphapca56' : ['-O2','-g','-mieee','-mtune=pca56'], + 'amd64' : ['-O2','-g'], + 'armv3l' : ['-O2','-g','-march=armv3'], + 'armv4b' : ['-O2','-g','-march=armv4'], + 'armv4l' : ['-O2','-g','-march=armv4'], + 'armv4tl' : ['-O2','-g','-march=armv4t'], + 'armv5tejl' : ['-O2','-g','-march=armv5te'], + 'armv5tel' : ['-O2','-g','-march=armv5te'], + 'armv6l' : ['-O2','-g','-march=armv6'], + 'armv7l' : ['-O2','-g','-march=armv7'], + 'atariclone' : ['-O2','-g','-fomit-frame-pointer'], + 'atarist' : ['-O2','-g','-fomit-frame-pointer'], + 'atariste' : ['-O2','-g','-fomit-frame-pointer'], + 'ataritt' : ['-O2','-g','-fomit-frame-pointer'], + 'athlon' : ['-O2','-g','-march=athlon'], + 'falcon' : ['-O2','-g','-fomit-frame-pointer'], + 'fat' : ['-O2','-g','-arch','i386','-arch','ppc'], + 'geode' : ['-Os','-g','-m32','-march=geode'], + 'hades' : ['-O2','-g','-fomit-frame-pointer'], + 'hppa1.0' : ['-O2','-g','-mpa-risc-1-0'], + 'hppa1.1' : ['-O2','-g','-mpa-risc-1-0'], + 'hppa1.2' : ['-O2','-g','-mpa-risc-1-0'], + 'hppa2.0' : ['-O2','-g','-mpa-risc-1-0'], + 'i386' : ['-O2','-g','-march=i386','-mtune=i686'], + 'i486' : ['-O2','-g','-march=i486'], + 'i586' : ['-O2','-g','-march=i586'], + 'i686' : ['-O2','-g','-march=i686'], + 'ia32e' : ['-O2','-g'], + 'ia64' : ['-O2','-g'], + 'm68k' : ['-O2','-g','-fomit-frame-pointer'], + 'milan' : ['-O2','-g','-fomit-frame-pointer'], + 'mips' : ['-O2','-g'], + 'mipsel' : ['-O2','-g'], + 'parisc' : ['-O2','-g','-mpa-risc-1-0'], + 'pentium3' : ['-O2','-g','-march=pentium3'], + 'pentium4' : ['-O2','-g','-march=pentium4'], + 'ppc' : ['-O2','-g','-fsigned-char'], + 'ppc32dy4' : ['-O2','-g','-fsigned-char'], + 'ppc64' : ['-O2','-g','-fsigned-char'], + 'ppc8260' : ['-O2','-g','-fsigned-char'], + 'ppc8560' : ['-O2','-g','-fsigned-char'], + 'ppciseries' : ['-O2','-g','-fsigned-char'], + 'ppcpseries' : ['-O2','-g','-fsigned-char'], + 's390' : ['-O2','-g'], + 's390x' : ['-O2','-g'], + 'sh3' : ['-O2','-g'], + 'sh4' : ['-O2','-g','-mieee'], + 'sh4a' : ['-O2','-g','-mieee'], + 'sparc' : ['-O2','-g','-m32','-mtune=ultrasparc'], + 'sparc64' : ['-O2','-g','-m64','-mtune=ultrasparc'], + 'sparc64v' : ['-O2','-g','-m64','-mtune=niagara'], + 'sparcv8' : ['-O2','-g','-m32','-mtune=ultrasparc','-mv8'], + 'sparcv9' : ['-O2','-g','-m32','-mtune=ultrasparc'], + 'sparcv9v' : ['-O2','-g','-m32','-mtune=niagara'], + 'x86_64' : ['-O2','-g'], +} + +arch_canon = { + 'IP' : ['sgi','7'], + 'alpha' : ['alpha','2'], + 'alphaev5' : ['alphaev5','2'], + 'alphaev56' : ['alphaev56','2'], + 'alphaev6' : ['alphaev6','2'], + 'alphaev67' : ['alphaev67','2'], + 'alphapca56' : ['alphapca56','2'], + 'amd64' : ['amd64','1'], + 'armv3l' : ['armv3l','12'], + 'armv4b' : ['armv4b','12'], + 'armv4l' : ['armv4l','12'], + 'armv5tejl' : ['armv5tejl','12'], + 'armv5tel' : ['armv5tel','12'], + 'armv6l' : ['armv6l','12'], + 'armv7l' : ['armv7l','12'], + 'atariclone' : ['m68kmint','13'], + 'atarist' : ['m68kmint','13'], + 'atariste' : ['m68kmint','13'], + 'ataritt' : ['m68kmint','13'], + 'athlon' : ['athlon','1'], + 'falcon' : ['m68kmint','13'], + 'geode' : ['geode','1'], + 'hades' : ['m68kmint','13'], + 'i370' : ['i370','14'], + 'i386' : ['i386','1'], + 'i486' : ['i486','1'], + 'i586' : ['i586','1'], + 'i686' : ['i686','1'], + 'ia32e' : ['ia32e','1'], + 'ia64' : ['ia64','9'], + 'm68k' : ['m68k','6'], + 'm68kmint' : ['m68kmint','13'], + 'milan' : ['m68kmint','13'], + 'mips' : ['mips','4'], + 'mipsel' : ['mipsel','11'], + 'pentium3' : ['pentium3','1'], + 'pentium4' : ['pentium4','1'], + 'ppc' : ['ppc','5'], + 'ppc32dy4' : ['ppc32dy4','5'], + 'ppc64' : ['ppc64','16'], + 'ppc64iseries' : ['ppc64iseries','16'], + 'ppc64pseries' : ['ppc64pseries','16'], + 'ppc8260' : ['ppc8260','5'], + 'ppc8560' : ['ppc8560','5'], + 'ppciseries' : ['ppciseries','5'], + 'ppcpseries' : ['ppcpseries','5'], + 'rs6000' : ['rs6000','8'], + 's390' : ['s390','14'], + 's390x' : ['s390x','15'], + 'sh' : ['sh','17'], + 'sh3' : ['sh3','17'], + 'sh4' : ['sh4','17'], + 'sh4a' : ['sh4a','17'], + 'sparc' : ['sparc','3'], + 'sparc64' : ['sparc64','2'], + 'sparc64v' : ['sparc64v','2'], + 'sparcv8' : ['sparcv8','3'], + 'sparcv9' : ['sparcv9','3'], + 'sparcv9v' : ['sparcv9v','3'], + 'sun4' : ['sparc','3'], + 'sun4c' : ['sparc','3'], + 'sun4d' : ['sparc','3'], + 'sun4m' : ['sparc','3'], + 'sun4u' : ['sparc64','2'], + 'x86_64' : ['x86_64','1'], + 'xtensa' : ['xtensa','18'], +} + +# End of rpmrc dictionaries (Marker, don't change or remove!) + +def defaultMachine(use_rpm_default=True): + """ Return the canonicalized machine name. """ + + if use_rpm_default: + try: + # This should be the most reliable way to get the default arch + rmachine = subprocess.check_output(['rpm', '--eval=%_target_cpu'], shell=False).rstrip() + rmachine = SCons.Util.to_str(rmachine) + except Exception as e: + # Something went wrong, try again by looking up platform.machine() + return defaultMachine(False) + else: + rmachine = platform.machine() + + # Try to lookup the string in the canon table + if rmachine in arch_canon: + rmachine = arch_canon[rmachine][0] + + return rmachine + +def defaultSystem(): + """ Return the canonicalized system name. """ + rsystem = platform.system() + + # Try to lookup the string in the canon tables + if rsystem in os_canon: + rsystem = os_canon[rsystem][0] + + return rsystem + +def defaultNames(): + """ Return the canonicalized machine and system name. """ + return defaultMachine(), defaultSystem() + +def updateRpmDicts(rpmrc, pyfile): + """ Read the given rpmrc file with RPM definitions and update the + info dictionaries in the file pyfile with it. + The arguments will usually be 'rpmrc.in' from a recent RPM source + tree, and 'rpmutils.py' referring to this script itself. + See also usage() below. + """ + try: + # Read old rpmutils.py file + oldpy = open(pyfile,"r").readlines() + # Read current rpmrc.in file + rpm = open(rpmrc,"r").readlines() + # Parse for data + data = {} + # Allowed section names that get parsed + sections = ['optflags', + 'arch_canon', + 'os_canon', + 'buildarchtranslate', + 'arch_compat', + 'os_compat', + 'buildarch_compat'] + for l in rpm: + l = l.rstrip('\n').replace(':',' ') + # Skip comments + if l.lstrip().startswith('#'): + continue + tokens = l.strip().split() + if len(tokens): + key = tokens[0] + if key in sections: + # Have we met this section before? + if tokens[0] not in data: + # No, so insert it + data[key] = {} + # Insert data + data[key][tokens[1]] = tokens[2:] + # Write new rpmutils.py file + out = open(pyfile,"w") + pm = 0 + for l in oldpy: + if pm: + if l.startswith('# End of rpmrc dictionaries'): + pm = 0 + out.write(l) + else: + out.write(l) + if l.startswith('# Start of rpmrc dictionaries'): + pm = 1 + # Write data sections to single dictionaries + for key, entries in data.items(): + out.write("%s = {\n" % key) + for arch in sorted(entries.keys()): + out.write(" '%s' : ['%s'],\n" % (arch, "','".join(entries[arch]))) + out.write("}\n\n") + out.close() + except: + pass + +def usage(): + print("rpmutils.py rpmrc.in rpmutils.py") + +def main(): + import sys + + if len(sys.argv) < 3: + usage() + sys.exit(0) + updateRpmDicts(sys.argv[1], sys.argv[2]) + +if __name__ == "__main__": + main() diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/sgiar.py b/tools/scons/scons-local-3.0.5/SCons/Tool/sgiar.py new file mode 100755 index 0000000000..feab04f1fc --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/sgiar.py @@ -0,0 +1,68 @@ +"""SCons.Tool.sgiar + +Tool-specific initialization for SGI ar (library archive). If CC +exists, static libraries should be built with it, so the prelinker has +a chance to resolve C++ template instantiations. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/sgiar.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Defaults +import SCons.Tool +import SCons.Util + +def generate(env): + """Add Builders and construction variables for ar to an Environment.""" + SCons.Tool.createStaticLibBuilder(env) + + if env.Detect('CC'): + env['AR'] = 'CC' + env['ARFLAGS'] = SCons.Util.CLVar('-ar') + env['ARCOM'] = '$AR $ARFLAGS -o $TARGET $SOURCES' + else: + env['AR'] = 'ar' + env['ARFLAGS'] = SCons.Util.CLVar('r') + env['ARCOM'] = '$AR $ARFLAGS $TARGET $SOURCES' + + env['SHLINK'] = '$LINK' + env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared') + env['SHLINKCOM'] = '$SHLINK $SHLINKFLAGS -o $TARGET $SOURCES $_LIBDIRFLAGS $_LIBFLAGS' + env['LIBPREFIX'] = 'lib' + env['LIBSUFFIX'] = '.a' + +def exists(env): + return env.Detect('CC') or env.Detect('ar') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/sgic++.py b/tools/scons/scons-local-3.0.5/SCons/Tool/sgic++.py new file mode 100755 index 0000000000..9d5fc96891 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/sgic++.py @@ -0,0 +1,43 @@ +"""SCons.Tool.sgic++ + +Tool-specific initialization for MIPSpro C++ on SGI. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/sgic++.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +#forward proxy to the preffered cxx version +from SCons.Tool.sgicxx import * + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/sgicc.py b/tools/scons/scons-local-3.0.5/SCons/Tool/sgicc.py new file mode 100755 index 0000000000..f957534427 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/sgicc.py @@ -0,0 +1,53 @@ +"""SCons.Tool.sgicc + +Tool-specific initialization for MIPSPro cc on SGI. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/sgicc.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +from . import cc + +def generate(env): + """Add Builders and construction variables for gcc to an Environment.""" + cc.generate(env) + + env['CXX'] = 'CC' + env['SHOBJSUFFIX'] = '.o' + env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1 + +def exists(env): + return env.Detect('cc') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/sgicxx.py b/tools/scons/scons-local-3.0.5/SCons/Tool/sgicxx.py new file mode 100755 index 0000000000..f4bfb8d31b --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/sgicxx.py @@ -0,0 +1,61 @@ +"""SCons.Tool.sgic++ + +Tool-specific initialization for MIPSpro C++ on SGI. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/sgicxx.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Util + +import SCons.Tool.cxx +cplusplus = SCons.Tool.cxx +#cplusplus = __import__('cxx', globals(), locals(), []) + + +def generate(env): + """Add Builders and construction variables for SGI MIPS C++ to an Environment.""" + + cplusplus.generate(env) + + env['CXX'] = 'CC' + env['CXXFLAGS'] = SCons.Util.CLVar('-LANG:std') + env['SHCXX'] = '$CXX' + env['SHOBJSUFFIX'] = '.o' + env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1 + +def exists(env): + return env.Detect('CC') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/sgilink.py b/tools/scons/scons-local-3.0.5/SCons/Tool/sgilink.py new file mode 100755 index 0000000000..fa64736a9b --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/sgilink.py @@ -0,0 +1,62 @@ +"""SCons.Tool.sgilink + +Tool-specific initialization for the SGI MIPSPro linker on SGI. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/sgilink.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Util + +from . import link + +linkers = ['CC', 'cc'] + +def generate(env): + """Add Builders and construction variables for MIPSPro to an Environment.""" + link.generate(env) + + env['LINK'] = env.Detect(linkers) or 'cc' + env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared') + + # __RPATH is set to $_RPATH in the platform specification if that + # platform supports it. + env['RPATHPREFIX'] = '-rpath ' + env['RPATHSUFFIX'] = '' + env['_RPATH'] = '${_concat(RPATHPREFIX, RPATH, RPATHSUFFIX, __env__)}' + +def exists(env): + return env.Detect(linkers) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/sunar.py b/tools/scons/scons-local-3.0.5/SCons/Tool/sunar.py new file mode 100755 index 0000000000..abce0a43f1 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/sunar.py @@ -0,0 +1,64 @@ +"""engine.SCons.Tool.sunar + +Tool-specific initialization for Solaris (Forte) ar (library archive). If CC +exists, static libraries should be built with it, so that template +instantiations can be resolved. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/sunar.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Defaults +import SCons.Tool +import SCons.Util + +def generate(env): + """Add Builders and construction variables for ar to an Environment.""" + SCons.Tool.createStaticLibBuilder(env) + + if env.Detect('CC'): + env['AR'] = 'CC' + env['ARFLAGS'] = SCons.Util.CLVar('-xar') + env['ARCOM'] = '$AR $ARFLAGS -o $TARGET $SOURCES' + else: + env['AR'] = 'ar' + env['ARFLAGS'] = SCons.Util.CLVar('r') + env['ARCOM'] = '$AR $ARFLAGS $TARGET $SOURCES' + + env['LIBPREFIX'] = 'lib' + env['LIBSUFFIX'] = '.a' + +def exists(env): + return env.Detect('CC') or env.Detect('ar') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/sunc++.py b/tools/scons/scons-local-3.0.5/SCons/Tool/sunc++.py new file mode 100755 index 0000000000..ef915f63a9 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/sunc++.py @@ -0,0 +1,45 @@ +"""SCons.Tool.sunc++ + +Tool-specific initialization for C++ on SunOS / Solaris. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/sunc++.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + + +#forward proxy to the preffered cxx version +from SCons.Tool.suncxx import * + + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/suncc.py b/tools/scons/scons-local-3.0.5/SCons/Tool/suncc.py new file mode 100755 index 0000000000..5b014027ce --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/suncc.py @@ -0,0 +1,58 @@ +"""SCons.Tool.suncc + +Tool-specific initialization for Sun Solaris (Forte) CC and cc. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/suncc.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Util + +from . import cc + +def generate(env): + """ + Add Builders and construction variables for Forte C and C++ compilers + to an Environment. + """ + cc.generate(env) + + env['CXX'] = 'CC' + env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS -KPIC') + env['SHOBJPREFIX'] = 'so_' + env['SHOBJSUFFIX'] = '.o' + +def exists(env): + return env.Detect('CC') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/suncxx.py b/tools/scons/scons-local-3.0.5/SCons/Tool/suncxx.py new file mode 100755 index 0000000000..d421946966 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/suncxx.py @@ -0,0 +1,144 @@ +"""SCons.Tool.sunc++ + +Tool-specific initialization for C++ on SunOS / Solaris. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/suncxx.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons + +import os +import re +import subprocess + +import SCons.Tool.cxx +cplusplus = SCons.Tool.cxx +#cplusplus = __import__('c++', globals(), locals(), []) + +package_info = {} + +def get_package_info(package_name, pkginfo, pkgchk): + try: + return package_info[package_name] + except KeyError: + version = None + pathname = None + try: + sadm_contents = open('/var/sadm/install/contents', 'r').read() + except EnvironmentError: + pass + else: + sadm_re = re.compile('^(\S*/bin/CC)(=\S*)? %s$' % package_name, re.M) + sadm_match = sadm_re.search(sadm_contents) + if sadm_match: + pathname = os.path.dirname(sadm_match.group(1)) + + try: + p = subprocess.Popen([pkginfo, '-l', package_name], + stdout=subprocess.PIPE, + stderr=open('/dev/null', 'w')) + except EnvironmentError: + pass + else: + pkginfo_contents = p.communicate()[0] + version_re = re.compile('^ *VERSION:\s*(.*)$', re.M) + version_match = version_re.search(pkginfo_contents) + if version_match: + version = version_match.group(1) + + if pathname is None: + try: + p = subprocess.Popen([pkgchk, '-l', package_name], + stdout=subprocess.PIPE, + stderr=open('/dev/null', 'w')) + except EnvironmentError: + pass + else: + pkgchk_contents = p.communicate()[0] + pathname_re = re.compile(r'^Pathname:\s*(.*/bin/CC)$', re.M) + pathname_match = pathname_re.search(pkgchk_contents) + if pathname_match: + pathname = os.path.dirname(pathname_match.group(1)) + + package_info[package_name] = (pathname, version) + return package_info[package_name] + +# use the package installer tool lslpp to figure out where cppc and what +# version of it is installed +def get_cppc(env): + cxx = env.subst('$CXX') + if cxx: + cppcPath = os.path.dirname(cxx) + else: + cppcPath = None + + cppcVersion = None + + pkginfo = env.subst('$PKGINFO') + pkgchk = env.subst('$PKGCHK') + + for package in ['SPROcpl']: + path, version = get_package_info(package, pkginfo, pkgchk) + if path and version: + cppcPath, cppcVersion = path, version + break + + return (cppcPath, 'CC', 'CC', cppcVersion) + +def generate(env): + """Add Builders and construction variables for SunPRO C++.""" + path, cxx, shcxx, version = get_cppc(env) + if path: + cxx = os.path.join(path, cxx) + shcxx = os.path.join(path, shcxx) + + cplusplus.generate(env) + + env['CXX'] = cxx + env['SHCXX'] = shcxx + env['CXXVERSION'] = version + env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS -KPIC') + env['SHOBJPREFIX'] = 'so_' + env['SHOBJSUFFIX'] = '.o' + +def exists(env): + path, cxx, shcxx, version = get_cppc(env) + if path and cxx: + cppc = os.path.join(path, cxx) + if os.path.exists(cppc): + return cppc + return None + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/sunf77.py b/tools/scons/scons-local-3.0.5/SCons/Tool/sunf77.py new file mode 100755 index 0000000000..9938d9191c --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/sunf77.py @@ -0,0 +1,63 @@ +"""SCons.Tool.sunf77 + +Tool-specific initialization for sunf77, the Sun Studio F77 compiler. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/sunf77.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Util + +from .FortranCommon import add_all_to_env + +compilers = ['sunf77', 'f77'] + +def generate(env): + """Add Builders and construction variables for sunf77 to an Environment.""" + add_all_to_env(env) + + fcomp = env.Detect(compilers) or 'f77' + env['FORTRAN'] = fcomp + env['F77'] = fcomp + + env['SHFORTRAN'] = '$FORTRAN' + env['SHF77'] = '$F77' + + env['SHFORTRANFLAGS'] = SCons.Util.CLVar('$FORTRANFLAGS -KPIC') + env['SHF77FLAGS'] = SCons.Util.CLVar('$F77FLAGS -KPIC') + +def exists(env): + return env.Detect(compilers) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/sunf90.py b/tools/scons/scons-local-3.0.5/SCons/Tool/sunf90.py new file mode 100755 index 0000000000..2f6ef97e0f --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/sunf90.py @@ -0,0 +1,64 @@ +"""SCons.Tool.sunf90 + +Tool-specific initialization for sunf90, the Sun Studio F90 compiler. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/sunf90.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Util + +from .FortranCommon import add_all_to_env + +compilers = ['sunf90', 'f90'] + +def generate(env): + """Add Builders and construction variables for sun f90 compiler to an + Environment.""" + add_all_to_env(env) + + fcomp = env.Detect(compilers) or 'f90' + env['FORTRAN'] = fcomp + env['F90'] = fcomp + + env['SHFORTRAN'] = '$FORTRAN' + env['SHF90'] = '$F90' + + env['SHFORTRANFLAGS'] = SCons.Util.CLVar('$FORTRANFLAGS -KPIC') + env['SHF90FLAGS'] = SCons.Util.CLVar('$F90FLAGS -KPIC') + +def exists(env): + return env.Detect(compilers) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/sunf95.py b/tools/scons/scons-local-3.0.5/SCons/Tool/sunf95.py new file mode 100755 index 0000000000..18541657e7 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/sunf95.py @@ -0,0 +1,64 @@ +"""SCons.Tool.sunf95 + +Tool-specific initialization for sunf95, the Sun Studio F95 compiler. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/sunf95.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Util + +from .FortranCommon import add_all_to_env + +compilers = ['sunf95', 'f95'] + +def generate(env): + """Add Builders and construction variables for sunf95 to an + Environment.""" + add_all_to_env(env) + + fcomp = env.Detect(compilers) or 'f95' + env['FORTRAN'] = fcomp + env['F95'] = fcomp + + env['SHFORTRAN'] = '$FORTRAN' + env['SHF95'] = '$F95' + + env['SHFORTRANFLAGS'] = SCons.Util.CLVar('$FORTRANFLAGS -KPIC') + env['SHF95FLAGS'] = SCons.Util.CLVar('$F95FLAGS -KPIC') + +def exists(env): + return env.Detect(compilers) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/sunlink.py b/tools/scons/scons-local-3.0.5/SCons/Tool/sunlink.py new file mode 100755 index 0000000000..28ec97164d --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/sunlink.py @@ -0,0 +1,80 @@ +"""SCons.Tool.sunlink + +Tool-specific initialization for the Sun Solaris (Forte) linker. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/sunlink.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os +import os.path + +import SCons.Util + +from . import link + +ccLinker = None + +# search for the acc compiler and linker front end + +try: + dirs = os.listdir('/opt') +except (IOError, OSError): + # Not being able to read the directory because it doesn't exist + # (IOError) or isn't readable (OSError) is okay. + dirs = [] + +for d in dirs: + linker = '/opt/' + d + '/bin/CC' + if os.path.exists(linker): + ccLinker = linker + break + +def generate(env): + """Add Builders and construction variables for Forte to an Environment.""" + link.generate(env) + + env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -G') + + env['RPATHPREFIX'] = '-R' + env['RPATHSUFFIX'] = '' + env['_RPATH'] = '${_concat(RPATHPREFIX, RPATH, RPATHSUFFIX, __env__)}' + + # Support for versioned libraries + link._setup_versioned_lib_variables(env, tool = 'sunlink', use_soname = True) + env['LINKCALLBACKS'] = link._versioned_lib_callbacks() + +def exists(env): + return ccLinker + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/swig.py b/tools/scons/scons-local-3.0.5/SCons/Tool/swig.py new file mode 100755 index 0000000000..a8d6400984 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/swig.py @@ -0,0 +1,218 @@ +"""SCons.Tool.swig + +Tool-specific initialization for swig. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" +from __future__ import print_function + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/swig.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os.path +import sys +import re +import subprocess + +import SCons.Action +import SCons.Defaults +import SCons.Tool +import SCons.Util +import SCons.Node + +verbose = False + +swigs = [ 'swig', 'swig3.0', 'swig2.0' ] + +SwigAction = SCons.Action.Action('$SWIGCOM', '$SWIGCOMSTR') + +def swigSuffixEmitter(env, source): + if '-c++' in SCons.Util.CLVar(env.subst("$SWIGFLAGS", source=source)): + return '$SWIGCXXFILESUFFIX' + else: + return '$SWIGCFILESUFFIX' + +# Match '%module test', as well as '%module(directors="1") test' +# Also allow for test to be quoted (SWIG permits double quotes, but not single) +# Also allow for the line to have spaces after test if not quoted +_reModule = re.compile(r'%module(\s*\(.*\))?\s+("?)(\S+)\2') + +def _find_modules(src): + """Find all modules referenced by %module lines in `src`, a SWIG .i file. + Returns a list of all modules, and a flag set if SWIG directors have + been requested (SWIG will generate an additional header file in this + case.)""" + directors = 0 + mnames = [] + try: + with open(src) as f: + data = f.read() + matches = _reModule.findall(data) + except IOError: + # If the file's not yet generated, guess the module name from the file stem + matches = [] + mnames.append(os.path.splitext(os.path.basename(src))[0]) + + for m in matches: + mnames.append(m[2]) + directors = directors or m[0].find('directors') >= 0 + return mnames, directors + +def _add_director_header_targets(target, env): + # Directors only work with C++ code, not C + suffix = env.subst(env['SWIGCXXFILESUFFIX']) + # For each file ending in SWIGCXXFILESUFFIX, add a new target director + # header by replacing the ending with SWIGDIRECTORSUFFIX. + for x in target[:]: + n = x.name + d = x.dir + if n[-len(suffix):] == suffix: + target.append(d.File(n[:-len(suffix)] + env['SWIGDIRECTORSUFFIX'])) + +def _swigEmitter(target, source, env): + swigflags = env.subst("$SWIGFLAGS", target=target, source=source) + flags = SCons.Util.CLVar(swigflags) + for src in source: + src = str(src.rfile()) + mnames = None + if "-python" in flags and "-noproxy" not in flags: + if mnames is None: + mnames, directors = _find_modules(src) + if directors: + _add_director_header_targets(target, env) + python_files = [m + ".py" for m in mnames] + outdir = env.subst('$SWIGOUTDIR', target=target, source=source) + # .py files should be generated in SWIGOUTDIR if specified, + # otherwise in the same directory as the target + if outdir: + python_files = [env.fs.File(os.path.join(outdir, j)) for j in python_files] + else: + python_files = [target[0].dir.File(m) for m in python_files] + target.extend(python_files) + if "-java" in flags: + if mnames is None: + mnames, directors = _find_modules(src) + if directors: + _add_director_header_targets(target, env) + java_files = [[m + ".java", m + "JNI.java"] for m in mnames] + java_files = SCons.Util.flatten(java_files) + outdir = env.subst('$SWIGOUTDIR', target=target, source=source) + if outdir: + java_files = [os.path.join(outdir, j) for j in java_files] + java_files = list(map(env.fs.File, java_files)) + def t_from_s(t, p, s, x): + return t.dir + tsm = SCons.Node._target_from_source_map + tkey = len(tsm) + tsm[tkey] = t_from_s + for jf in java_files: + jf._func_target_from_source = tkey + target.extend(java_files) + return (target, source) + +def _get_swig_version(env, swig): + """Run the SWIG command line tool to get and return the version number""" + version = None + swig = env.subst(swig) + if not swig: + return version + pipe = SCons.Action._subproc(env, SCons.Util.CLVar(swig) + ['-version'], + stdin = 'devnull', + stderr = 'devnull', + stdout = subprocess.PIPE) + if pipe.wait() != 0: + return version + + # MAYBE: out = SCons.Util.to_str (pipe.stdout.read()) + with pipe.stdout: + out = SCons.Util.to_str(pipe.stdout.read()) + + match = re.search(r'SWIG Version\s+(\S+).*', out, re.MULTILINE) + if match: + version = match.group(1) + if verbose: + print("Version is: %s" % version) + else: + if verbose: + print("Unable to detect version: [%s]" % out) + + return version + +def generate(env): + """Add Builders and construction variables for swig to an Environment.""" + c_file, cxx_file = SCons.Tool.createCFileBuilders(env) + + c_file.suffix['.i'] = swigSuffixEmitter + cxx_file.suffix['.i'] = swigSuffixEmitter + + c_file.add_action('.i', SwigAction) + c_file.add_emitter('.i', _swigEmitter) + cxx_file.add_action('.i', SwigAction) + cxx_file.add_emitter('.i', _swigEmitter) + + java_file = SCons.Tool.CreateJavaFileBuilder(env) + + java_file.suffix['.i'] = swigSuffixEmitter + + java_file.add_action('.i', SwigAction) + java_file.add_emitter('.i', _swigEmitter) + + from SCons.Platform.mingw import MINGW_DEFAULT_PATHS + from SCons.Platform.cygwin import CYGWIN_DEFAULT_PATHS + + if sys.platform == 'win32': + swig = SCons.Tool.find_program_path(env, 'swig', default_paths=MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS + [r'C:\ProgramData\chocolatey\bin'] ) + if swig: + swig_bin_dir = os.path.dirname(swig) + env.AppendENVPath('PATH', swig_bin_dir) + else: + SCons.Warnings.Warning('swig tool requested, but binary not found in ENV PATH') + + if 'SWIG' not in env: + env['SWIG'] = env.Detect(swigs) or swigs[0] + env['SWIGVERSION'] = _get_swig_version(env, env['SWIG']) + env['SWIGFLAGS'] = SCons.Util.CLVar('') + env['SWIGDIRECTORSUFFIX'] = '_wrap.h' + env['SWIGCFILESUFFIX'] = '_wrap$CFILESUFFIX' + env['SWIGCXXFILESUFFIX'] = '_wrap$CXXFILESUFFIX' + env['_SWIGOUTDIR'] = r'${"-outdir \"%s\"" % SWIGOUTDIR}' + env['SWIGPATH'] = [] + env['SWIGINCPREFIX'] = '-I' + env['SWIGINCSUFFIX'] = '' + env['_SWIGINCFLAGS'] = '$( ${_concat(SWIGINCPREFIX, SWIGPATH, SWIGINCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)' + env['SWIGCOM'] = '$SWIG -o $TARGET ${_SWIGOUTDIR} ${_SWIGINCFLAGS} $SWIGFLAGS $SOURCES' + +def exists(env): + swig = env.get('SWIG') or env.Detect(['swig']) + return swig + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/tar.py b/tools/scons/scons-local-3.0.5/SCons/Tool/tar.py new file mode 100755 index 0000000000..05a7c70033 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/tar.py @@ -0,0 +1,73 @@ +"""SCons.Tool.tar + +Tool-specific initialization for tar. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/tar.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Action +import SCons.Builder +import SCons.Defaults +import SCons.Node.FS +import SCons.Util + +tars = ['tar', 'gtar'] + +TarAction = SCons.Action.Action('$TARCOM', '$TARCOMSTR') + +TarBuilder = SCons.Builder.Builder(action = TarAction, + source_factory = SCons.Node.FS.Entry, + source_scanner = SCons.Defaults.DirScanner, + suffix = '$TARSUFFIX', + multi = 1) + + +def generate(env): + """Add Builders and construction variables for tar to an Environment.""" + try: + bld = env['BUILDERS']['Tar'] + except KeyError: + bld = TarBuilder + env['BUILDERS']['Tar'] = bld + + env['TAR'] = env.Detect(tars) or 'gtar' + env['TARFLAGS'] = SCons.Util.CLVar('-c') + env['TARCOM'] = '$TAR $TARFLAGS -f $TARGET $SOURCES' + env['TARSUFFIX'] = '.tar' + +def exists(env): + return env.Detect(tars) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/tex.py b/tools/scons/scons-local-3.0.5/SCons/Tool/tex.py new file mode 100755 index 0000000000..4607d2f6e2 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/tex.py @@ -0,0 +1,993 @@ +"""SCons.Tool.tex + +Tool-specific initialization for TeX. +Generates .dvi files from .tex files + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +from __future__ import print_function + +__revision__ = "src/engine/SCons/Tool/tex.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os.path +import re +import shutil +import sys +import platform +import glob + +import SCons.Action +import SCons.Node +import SCons.Node.FS +import SCons.Util +import SCons.Scanner.LaTeX + +Verbose = False + +must_rerun_latex = True + +# these are files that just need to be checked for changes and then rerun latex +check_suffixes = ['.toc', '.lof', '.lot', '.out', '.nav', '.snm'] + +# these are files that require bibtex or makeindex to be run when they change +all_suffixes = check_suffixes + ['.bbl', '.idx', '.nlo', '.glo', '.acn', '.bcf'] + +# +# regular expressions used to search for Latex features +# or outputs that require rerunning latex +# +# search for all .aux files opened by latex (recorded in the .fls file) +openout_aux_re = re.compile(r"OUTPUT *(.*\.aux)") + +# search for all .bcf files opened by latex (recorded in the .fls file) +# for use by biber +openout_bcf_re = re.compile(r"OUTPUT *(.*\.bcf)") + +#printindex_re = re.compile(r"^[^%]*\\printindex", re.MULTILINE) +#printnomenclature_re = re.compile(r"^[^%]*\\printnomenclature", re.MULTILINE) +#printglossary_re = re.compile(r"^[^%]*\\printglossary", re.MULTILINE) + +# search to find rerun warnings +warning_rerun_str = r'(^LaTeX Warning:.*Rerun)|(^Package \w+ Warning:.*Rerun)' +warning_rerun_re = re.compile(warning_rerun_str, re.MULTILINE) + +# search to find citation rerun warnings +rerun_citations_str = r"^LaTeX Warning:.*\n.*Rerun to get citations correct" +rerun_citations_re = re.compile(rerun_citations_str, re.MULTILINE) + +# search to find undefined references or citations warnings +undefined_references_str = r'(^LaTeX Warning:.*undefined references)|(^Package \w+ Warning:.*undefined citations)' +undefined_references_re = re.compile(undefined_references_str, re.MULTILINE) + +# used by the emitter +auxfile_re = re.compile(r".", re.MULTILINE) +tableofcontents_re = re.compile(r"^[^%\n]*\\tableofcontents", re.MULTILINE) +makeindex_re = re.compile(r"^[^%\n]*\\makeindex", re.MULTILINE) +bibliography_re = re.compile(r"^[^%\n]*\\bibliography", re.MULTILINE) +bibunit_re = re.compile(r"^[^%\n]*\\begin\{bibunit\}", re.MULTILINE) +multibib_re = re.compile(r"^[^%\n]*\\newcites\{([^\}]*)\}", re.MULTILINE) +addbibresource_re = re.compile(r"^[^%\n]*\\(addbibresource|addglobalbib|addsectionbib)", re.MULTILINE) +listoffigures_re = re.compile(r"^[^%\n]*\\listoffigures", re.MULTILINE) +listoftables_re = re.compile(r"^[^%\n]*\\listoftables", re.MULTILINE) +hyperref_re = re.compile(r"^[^%\n]*\\usepackage.*\{hyperref\}", re.MULTILINE) +makenomenclature_re = re.compile(r"^[^%\n]*\\makenomenclature", re.MULTILINE) +makeglossary_re = re.compile(r"^[^%\n]*\\makeglossary", re.MULTILINE) +makeglossaries_re = re.compile(r"^[^%\n]*\\makeglossaries", re.MULTILINE) +makeacronyms_re = re.compile(r"^[^%\n]*\\makeglossaries", re.MULTILINE) +beamer_re = re.compile(r"^[^%\n]*\\documentclass\{beamer\}", re.MULTILINE) +regex = r'^[^%\n]*\\newglossary\s*\[([^\]]+)\]?\s*\{([^}]*)\}\s*\{([^}]*)\}\s*\{([^}]*)\}\s*\{([^}]*)\}' +newglossary_re = re.compile(regex, re.MULTILINE) +biblatex_re = re.compile(r"^[^%\n]*\\usepackage.*\{biblatex\}", re.MULTILINE) + +newglossary_suffix = [] + +# search to find all files included by Latex +include_re = re.compile(r'^[^%\n]*\\(?:include|input){([^}]*)}', re.MULTILINE) +includeOnly_re = re.compile(r'^[^%\n]*\\(?:include){([^}]*)}', re.MULTILINE) + +# search to find all graphics files included by Latex +includegraphics_re = re.compile(r'^[^%\n]*\\(?:includegraphics(?:\[[^\]]+\])?){([^}]*)}', re.MULTILINE) + +# search to find all files opened by Latex (recorded in .log file) +openout_re = re.compile(r"OUTPUT *(.*)") + +# list of graphics file extensions for TeX and LaTeX +TexGraphics = SCons.Scanner.LaTeX.TexGraphics +LatexGraphics = SCons.Scanner.LaTeX.LatexGraphics + +# An Action sufficient to build any generic tex file. +TeXAction = None + +# An action to build a latex file. This action might be needed more +# than once if we are dealing with labels and bibtex. +LaTeXAction = None + +# An action to run BibTeX on a file. +BibTeXAction = None + +# An action to run Biber on a file. +BiberAction = None + +# An action to run MakeIndex on a file. +MakeIndexAction = None + +# An action to run MakeIndex (for nomencl) on a file. +MakeNclAction = None + +# An action to run MakeIndex (for glossary) on a file. +MakeGlossaryAction = None + +# An action to run MakeIndex (for acronyms) on a file. +MakeAcronymsAction = None + +# An action to run MakeIndex (for newglossary commands) on a file. +MakeNewGlossaryAction = None + +# Used as a return value of modify_env_var if the variable is not set. +_null = SCons.Scanner.LaTeX._null + +modify_env_var = SCons.Scanner.LaTeX.modify_env_var + +def check_file_error_message(utility, filename='log'): + msg = '%s returned an error, check the %s file\n' % (utility, filename) + sys.stdout.write(msg) + +def FindFile(name,suffixes,paths,env,requireExt=False): + if requireExt: + name,ext = SCons.Util.splitext(name) + # if the user gave an extension use it. + if ext: + name = name + ext + if Verbose: + print(" searching for '%s' with extensions: " % name,suffixes) + + for path in paths: + testName = os.path.join(path,name) + if Verbose: + print(" look for '%s'" % testName) + if os.path.isfile(testName): + if Verbose: + print(" found '%s'" % testName) + return env.fs.File(testName) + else: + name_ext = SCons.Util.splitext(testName)[1] + if name_ext: + continue + + # if no suffix try adding those passed in + for suffix in suffixes: + testNameExt = testName + suffix + if Verbose: + print(" look for '%s'" % testNameExt) + + if os.path.isfile(testNameExt): + if Verbose: + print(" found '%s'" % testNameExt) + return env.fs.File(testNameExt) + if Verbose: + print(" did not find '%s'" % name) + return None + +def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None): + """A builder for LaTeX files that checks the output in the aux file + and decides how many times to use LaTeXAction, and BibTeXAction.""" + + global must_rerun_latex + + # This routine is called with two actions. In this file for DVI builds + # with LaTeXAction and from the pdflatex.py with PDFLaTeXAction + # set this up now for the case where the user requests a different extension + # for the target filename + if (XXXLaTeXAction == LaTeXAction): + callerSuffix = ".dvi" + else: + callerSuffix = env['PDFSUFFIX'] + + basename = SCons.Util.splitext(str(source[0]))[0] + basedir = os.path.split(str(source[0]))[0] + basefile = os.path.split(str(basename))[1] + abspath = os.path.abspath(basedir) + + targetext = os.path.splitext(str(target[0]))[1] + targetdir = os.path.split(str(target[0]))[0] + + saved_env = {} + for var in SCons.Scanner.LaTeX.LaTeX.env_variables: + saved_env[var] = modify_env_var(env, var, abspath) + + # Create base file names with the target directory since the auxiliary files + # will be made there. That's because the *COM variables have the cd + # command in the prolog. We check + # for the existence of files before opening them--even ones like the + # aux file that TeX always creates--to make it possible to write tests + # with stubs that don't necessarily generate all of the same files. + + targetbase = os.path.join(targetdir, basefile) + + # if there is a \makeindex there will be a .idx and thus + # we have to run makeindex at least once to keep the build + # happy even if there is no index. + # Same for glossaries, nomenclature, and acronyms + src_content = source[0].get_text_contents() + run_makeindex = makeindex_re.search(src_content) and not os.path.isfile(targetbase + '.idx') + run_nomenclature = makenomenclature_re.search(src_content) and not os.path.isfile(targetbase + '.nlo') + run_glossary = makeglossary_re.search(src_content) and not os.path.isfile(targetbase + '.glo') + run_glossaries = makeglossaries_re.search(src_content) and not os.path.isfile(targetbase + '.glo') + run_acronyms = makeacronyms_re.search(src_content) and not os.path.isfile(targetbase + '.acn') + + saved_hashes = {} + suffix_nodes = {} + + + for suffix in all_suffixes+sum(newglossary_suffix, []): + theNode = env.fs.File(targetbase + suffix) + suffix_nodes[suffix] = theNode + saved_hashes[suffix] = theNode.get_csig() + + if Verbose: + print("hashes: ",saved_hashes) + + must_rerun_latex = True + + # .aux files already processed by BibTex + already_bibtexed = [] + + # + # routine to update MD5 hash and compare + # + def check_MD5(filenode, suffix): + global must_rerun_latex + # two calls to clear old csig + filenode.clear_memoized_values() + filenode.ninfo = filenode.new_ninfo() + new_md5 = filenode.get_csig() + + if saved_hashes[suffix] == new_md5: + if Verbose: + print("file %s not changed" % (targetbase+suffix)) + return False # unchanged + saved_hashes[suffix] = new_md5 + must_rerun_latex = True + if Verbose: + print("file %s changed, rerunning Latex, new hash = " % (targetbase+suffix), new_md5) + return True # changed + + # generate the file name that latex will generate + resultfilename = targetbase + callerSuffix + + count = 0 + + while (must_rerun_latex and count < int(env.subst('$LATEXRETRIES'))) : + result = XXXLaTeXAction(target, source, env) + if result != 0: + return result + + count = count + 1 + + must_rerun_latex = False + # Decide if various things need to be run, or run again. + + # Read the log file to find warnings/errors + logfilename = targetbase + '.log' + logContent = '' + if os.path.isfile(logfilename): + with open(logfilename, "r") as f: + logContent = f.read() + + + # Read the fls file to find all .aux files + flsfilename = targetbase + '.fls' + flsContent = '' + auxfiles = [] + if os.path.isfile(flsfilename): + with open(flsfilename, "r") as f: + flsContent = f.read() + auxfiles = openout_aux_re.findall(flsContent) + # remove duplicates + dups = {} + for x in auxfiles: + dups[x] = 1 + auxfiles = list(dups.keys()) + + bcffiles = [] + if os.path.isfile(flsfilename): + with open(flsfilename, "r") as f: + flsContent = f.read() + bcffiles = openout_bcf_re.findall(flsContent) + # remove duplicates + dups = {} + for x in bcffiles: + dups[x] = 1 + bcffiles = list(dups.keys()) + + if Verbose: + print("auxfiles ",auxfiles) + print("bcffiles ",bcffiles) + + # Now decide if bibtex will need to be run. + # The information that bibtex reads from the .aux file is + # pass-independent. If we find (below) that the .bbl file is unchanged, + # then the last latex saw a correct bibliography. + # Therefore only do this once + # Go through all .aux files and remember the files already done. + for auxfilename in auxfiles: + if auxfilename not in already_bibtexed: + already_bibtexed.append(auxfilename) + target_aux = os.path.join(targetdir, auxfilename) + if os.path.isfile(target_aux): + with open(target_aux, "r") as f: + content = f.read() + if content.find("bibdata") != -1: + if Verbose: + print("Need to run bibtex on ",auxfilename) + bibfile = env.fs.File(SCons.Util.splitext(target_aux)[0]) + result = BibTeXAction(bibfile, bibfile, env) + if result != 0: + check_file_error_message(env['BIBTEX'], 'blg') + must_rerun_latex = True + + # Now decide if biber will need to be run. + # When the backend for biblatex is biber (by choice or default) the + # citation information is put in the .bcf file. + # The information that biber reads from the .bcf file is + # pass-independent. If we find (below) that the .bbl file is unchanged, + # then the last latex saw a correct bibliography. + # Therefore only do this once + # Go through all .bcf files and remember the files already done. + for bcffilename in bcffiles: + if bcffilename not in already_bibtexed: + already_bibtexed.append(bcffilename) + target_bcf = os.path.join(targetdir, bcffilename) + if os.path.isfile(target_bcf): + with open(target_bcf, "r") as f: + content = f.read() + if content.find("bibdata") != -1: + if Verbose: + print("Need to run biber on ",bcffilename) + bibfile = env.fs.File(SCons.Util.splitext(target_bcf)[0]) + result = BiberAction(bibfile, bibfile, env) + if result != 0: + check_file_error_message(env['BIBER'], 'blg') + must_rerun_latex = True + + # Now decide if latex will need to be run again due to index. + if check_MD5(suffix_nodes['.idx'],'.idx') or (count == 1 and run_makeindex): + # We must run makeindex + if Verbose: + print("Need to run makeindex") + idxfile = suffix_nodes['.idx'] + result = MakeIndexAction(idxfile, idxfile, env) + if result != 0: + check_file_error_message(env['MAKEINDEX'], 'ilg') + return result + + # TO-DO: need to add a way for the user to extend this list for whatever + # auxiliary files they create in other (or their own) packages + # Harder is case is where an action needs to be called -- that should be rare (I hope?) + + for index in check_suffixes: + check_MD5(suffix_nodes[index],index) + + # Now decide if latex will need to be run again due to nomenclature. + if check_MD5(suffix_nodes['.nlo'],'.nlo') or (count == 1 and run_nomenclature): + # We must run makeindex + if Verbose: + print("Need to run makeindex for nomenclature") + nclfile = suffix_nodes['.nlo'] + result = MakeNclAction(nclfile, nclfile, env) + if result != 0: + check_file_error_message('%s (nomenclature)' % env['MAKENCL'], + 'nlg') + #return result + + # Now decide if latex will need to be run again due to glossary. + if check_MD5(suffix_nodes['.glo'],'.glo') or (count == 1 and run_glossaries) or (count == 1 and run_glossary): + # We must run makeindex + if Verbose: + print("Need to run makeindex for glossary") + glofile = suffix_nodes['.glo'] + result = MakeGlossaryAction(glofile, glofile, env) + if result != 0: + check_file_error_message('%s (glossary)' % env['MAKEGLOSSARY'], + 'glg') + #return result + + # Now decide if latex will need to be run again due to acronyms. + if check_MD5(suffix_nodes['.acn'],'.acn') or (count == 1 and run_acronyms): + # We must run makeindex + if Verbose: + print("Need to run makeindex for acronyms") + acrfile = suffix_nodes['.acn'] + result = MakeAcronymsAction(acrfile, acrfile, env) + if result != 0: + check_file_error_message('%s (acronyms)' % env['MAKEACRONYMS'], + 'alg') + return result + + # Now decide if latex will need to be run again due to newglossary command. + for ig in range(len(newglossary_suffix)): + if check_MD5(suffix_nodes[newglossary_suffix[ig][2]],newglossary_suffix[ig][2]) or (count == 1): + # We must run makeindex + if Verbose: + print("Need to run makeindex for newglossary") + newglfile = suffix_nodes[newglossary_suffix[ig][2]] + MakeNewGlossaryAction = SCons.Action.Action("$MAKENEWGLOSSARYCOM ${SOURCE.filebase}%s -s ${SOURCE.filebase}.ist -t ${SOURCE.filebase}%s -o ${SOURCE.filebase}%s" % (newglossary_suffix[ig][2],newglossary_suffix[ig][0],newglossary_suffix[ig][1]), "$MAKENEWGLOSSARYCOMSTR") + + result = MakeNewGlossaryAction(newglfile, newglfile, env) + if result != 0: + check_file_error_message('%s (newglossary)' % env['MAKENEWGLOSSARY'], + newglossary_suffix[ig][0]) + return result + + # Now decide if latex needs to be run yet again to resolve warnings. + if warning_rerun_re.search(logContent): + must_rerun_latex = True + if Verbose: + print("rerun Latex due to latex or package rerun warning") + + if rerun_citations_re.search(logContent): + must_rerun_latex = True + if Verbose: + print("rerun Latex due to 'Rerun to get citations correct' warning") + + if undefined_references_re.search(logContent): + must_rerun_latex = True + if Verbose: + print("rerun Latex due to undefined references or citations") + + if (count >= int(env.subst('$LATEXRETRIES')) and must_rerun_latex): + print("reached max number of retries on Latex ,",int(env.subst('$LATEXRETRIES'))) +# end of while loop + + # rename Latex's output to what the target name is + if not (str(target[0]) == resultfilename and os.path.isfile(resultfilename)): + if os.path.isfile(resultfilename): + print("move %s to %s" % (resultfilename, str(target[0]), )) + shutil.move(resultfilename,str(target[0])) + + # Original comment (when TEXPICTS was not restored): + # The TEXPICTS enviroment variable is needed by a dvi -> pdf step + # later on Mac OSX so leave it + # + # It is also used when searching for pictures (implicit dependencies). + # Why not set the variable again in the respective builder instead + # of leaving local modifications in the environment? What if multiple + # latex builds in different directories need different TEXPICTS? + for var in SCons.Scanner.LaTeX.LaTeX.env_variables: + if var == 'TEXPICTS': + continue + if saved_env[var] is _null: + try: + del env['ENV'][var] + except KeyError: + pass # was never set + else: + env['ENV'][var] = saved_env[var] + + return result + +def LaTeXAuxAction(target = None, source= None, env=None): + result = InternalLaTeXAuxAction( LaTeXAction, target, source, env ) + return result + +LaTeX_re = re.compile("\\\\document(style|class)") + +def is_LaTeX(flist,env,abspath): + """Scan a file list to decide if it's TeX- or LaTeX-flavored.""" + + # We need to scan files that are included in case the + # \documentclass command is in them. + + # get path list from both env['TEXINPUTS'] and env['ENV']['TEXINPUTS'] + savedpath = modify_env_var(env, 'TEXINPUTS', abspath) + paths = env['ENV']['TEXINPUTS'] + if SCons.Util.is_List(paths): + pass + else: + # Split at os.pathsep to convert into absolute path + paths = paths.split(os.pathsep) + + # now that we have the path list restore the env + if savedpath is _null: + try: + del env['ENV']['TEXINPUTS'] + except KeyError: + pass # was never set + else: + env['ENV']['TEXINPUTS'] = savedpath + if Verbose: + print("is_LaTeX search path ",paths) + print("files to search :",flist) + + # Now that we have the search path and file list, check each one + for f in flist: + if Verbose: + print(" checking for Latex source ",str(f)) + + content = f.get_text_contents() + if LaTeX_re.search(content): + if Verbose: + print("file %s is a LaTeX file" % str(f)) + return 1 + if Verbose: + print("file %s is not a LaTeX file" % str(f)) + + # now find included files + inc_files = [ ] + inc_files.extend( include_re.findall(content) ) + if Verbose: + print("files included by '%s': "%str(f),inc_files) + # inc_files is list of file names as given. need to find them + # using TEXINPUTS paths. + + # search the included files + for src in inc_files: + srcNode = FindFile(src,['.tex','.ltx','.latex'],paths,env,requireExt=False) + # make this a list since is_LaTeX takes a list. + fileList = [srcNode,] + if Verbose: + print("FindFile found ",srcNode) + if srcNode is not None: + file_test = is_LaTeX(fileList, env, abspath) + + # return on first file that finds latex is needed. + if file_test: + return file_test + + if Verbose: + print(" done scanning ",str(f)) + + return 0 + +def TeXLaTeXFunction(target = None, source= None, env=None): + """A builder for TeX and LaTeX that scans the source file to + decide the "flavor" of the source and then executes the appropriate + program.""" + + # find these paths for use in is_LaTeX to search for included files + basedir = os.path.split(str(source[0]))[0] + abspath = os.path.abspath(basedir) + + if is_LaTeX(source,env,abspath): + result = LaTeXAuxAction(target,source,env) + if result != 0: + check_file_error_message(env['LATEX']) + else: + result = TeXAction(target,source,env) + if result != 0: + check_file_error_message(env['TEX']) + return result + +def TeXLaTeXStrFunction(target = None, source= None, env=None): + """A strfunction for TeX and LaTeX that scans the source file to + decide the "flavor" of the source and then returns the appropriate + command string.""" + if env.GetOption("no_exec"): + + # find these paths for use in is_LaTeX to search for included files + basedir = os.path.split(str(source[0]))[0] + abspath = os.path.abspath(basedir) + + if is_LaTeX(source,env,abspath): + result = env.subst('$LATEXCOM',0,target,source)+" ..." + else: + result = env.subst("$TEXCOM",0,target,source)+" ..." + else: + result = '' + return result + +def tex_eps_emitter(target, source, env): + """An emitter for TeX and LaTeX sources when + executing tex or latex. It will accept .ps and .eps + graphics files + """ + (target, source) = tex_emitter_core(target, source, env, TexGraphics) + + return (target, source) + +def tex_pdf_emitter(target, source, env): + """An emitter for TeX and LaTeX sources when + executing pdftex or pdflatex. It will accept graphics + files of types .pdf, .jpg, .png, .gif, and .tif + """ + (target, source) = tex_emitter_core(target, source, env, LatexGraphics) + + return (target, source) + +def ScanFiles(theFile, target, paths, file_tests, file_tests_search, env, graphics_extensions, targetdir, aux_files): + """ For theFile (a Node) update any file_tests and search for graphics files + then find all included files and call ScanFiles recursively for each of them""" + + content = theFile.get_text_contents() + if Verbose: + print(" scanning ",str(theFile)) + + for i in range(len(file_tests_search)): + if file_tests[i][0] is None: + if Verbose: + print("scan i ",i," files_tests[i] ",file_tests[i], file_tests[i][1]) + file_tests[i][0] = file_tests_search[i].search(content) + if Verbose and file_tests[i][0]: + print(" found match for ",file_tests[i][1][-1]) + # for newglossary insert the suffixes in file_tests[i] + if file_tests[i][0] and file_tests[i][1][-1] == 'newglossary': + findresult = file_tests_search[i].findall(content) + for l in range(len(findresult)) : + (file_tests[i][1]).insert(0,'.'+findresult[l][3]) + (file_tests[i][1]).insert(0,'.'+findresult[l][2]) + (file_tests[i][1]).insert(0,'.'+findresult[l][0]) + suffix_list = ['.'+findresult[l][0],'.'+findresult[l][2],'.'+findresult[l][3] ] + newglossary_suffix.append(suffix_list) + if Verbose: + print(" new suffixes for newglossary ",newglossary_suffix) + + + incResult = includeOnly_re.search(content) + if incResult: + aux_files.append(os.path.join(targetdir, incResult.group(1))) + if Verbose: + print(r"\include file names : ", aux_files) + # recursively call this on each of the included files + inc_files = [ ] + inc_files.extend( include_re.findall(content) ) + if Verbose: + print("files included by '%s': "%str(theFile),inc_files) + # inc_files is list of file names as given. need to find them + # using TEXINPUTS paths. + + for src in inc_files: + srcNode = FindFile(src,['.tex','.ltx','.latex'],paths,env,requireExt=False) + if srcNode is not None: + file_tests = ScanFiles(srcNode, target, paths, file_tests, file_tests_search, env, graphics_extensions, targetdir, aux_files) + if Verbose: + print(" done scanning ",str(theFile)) + return file_tests + +def tex_emitter_core(target, source, env, graphics_extensions): + """An emitter for TeX and LaTeX sources. + For LaTeX sources we try and find the common created files that + are needed on subsequent runs of latex to finish tables of contents, + bibliographies, indices, lists of figures, and hyperlink references. + """ + basename = SCons.Util.splitext(str(source[0]))[0] + basefile = os.path.split(str(basename))[1] + targetdir = os.path.split(str(target[0]))[0] + targetbase = os.path.join(targetdir, basefile) + + basedir = os.path.split(str(source[0]))[0] + abspath = os.path.abspath(basedir) + target[0].attributes.path = abspath + + # + # file names we will make use of in searching the sources and log file + # + emit_suffixes = ['.aux', '.log', '.ilg', '.blg', '.nls', '.nlg', '.gls', '.glg', '.alg'] + all_suffixes + auxfilename = targetbase + '.aux' + logfilename = targetbase + '.log' + flsfilename = targetbase + '.fls' + syncfilename = targetbase + '.synctex.gz' + + env.SideEffect(auxfilename,target[0]) + env.SideEffect(logfilename,target[0]) + env.SideEffect(flsfilename,target[0]) + env.SideEffect(syncfilename,target[0]) + if Verbose: + print("side effect :",auxfilename,logfilename,flsfilename,syncfilename) + env.Clean(target[0],auxfilename) + env.Clean(target[0],logfilename) + env.Clean(target[0],flsfilename) + env.Clean(target[0],syncfilename) + + content = source[0].get_text_contents() + + # set up list with the regular expressions + # we use to find features used + file_tests_search = [auxfile_re, + makeindex_re, + bibliography_re, + bibunit_re, + multibib_re, + addbibresource_re, + tableofcontents_re, + listoffigures_re, + listoftables_re, + hyperref_re, + makenomenclature_re, + makeglossary_re, + makeglossaries_re, + makeacronyms_re, + beamer_re, + newglossary_re, + biblatex_re ] + # set up list with the file suffixes that need emitting + # when a feature is found + file_tests_suff = [['.aux','aux_file'], + ['.idx', '.ind', '.ilg','makeindex'], + ['.bbl', '.blg','bibliography'], + ['.bbl', '.blg','bibunit'], + ['.bbl', '.blg','multibib'], + ['.bbl', '.blg','.bcf','addbibresource'], + ['.toc','contents'], + ['.lof','figures'], + ['.lot','tables'], + ['.out','hyperref'], + ['.nlo', '.nls', '.nlg','nomenclature'], + ['.glo', '.gls', '.glg','glossary'], + ['.glo', '.gls', '.glg','glossaries'], + ['.acn', '.acr', '.alg','acronyms'], + ['.nav', '.snm', '.out', '.toc','beamer'], + ['newglossary',], + ['.bcf', '.blg','biblatex'] ] + # for newglossary the suffixes are added as we find the command + # build the list of lists + file_tests = [] + for i in range(len(file_tests_search)): + file_tests.append( [None, file_tests_suff[i]] ) + + # TO-DO: need to add a way for the user to extend this list for whatever + # auxiliary files they create in other (or their own) packages + + # get path list from both env['TEXINPUTS'] and env['ENV']['TEXINPUTS'] + savedpath = modify_env_var(env, 'TEXINPUTS', abspath) + paths = env['ENV']['TEXINPUTS'] + if SCons.Util.is_List(paths): + pass + else: + # Split at os.pathsep to convert into absolute path + paths = paths.split(os.pathsep) + + # now that we have the path list restore the env + if savedpath is _null: + try: + del env['ENV']['TEXINPUTS'] + except KeyError: + pass # was never set + else: + env['ENV']['TEXINPUTS'] = savedpath + if Verbose: + print("search path ",paths) + + # scan all sources for side effect files + aux_files = [] + file_tests = ScanFiles(source[0], target, paths, file_tests, file_tests_search, env, graphics_extensions, targetdir, aux_files) + + for (theSearch,suffix_list) in file_tests: + # add side effects if feature is present.If file is to be generated,add all side effects + if Verbose and theSearch: + print("check side effects for ",suffix_list[-1]) + if (theSearch != None) or (not source[0].exists() ): + file_list = [targetbase,] + # for bibunit we need a list of files + if suffix_list[-1] == 'bibunit': + file_basename = os.path.join(targetdir, 'bu*.aux') + file_list = glob.glob(file_basename) + # remove the suffix '.aux' + for i in range(len(file_list)): + file_list.append(SCons.Util.splitext(file_list[i])[0]) + # for multibib we need a list of files + if suffix_list[-1] == 'multibib': + for multibibmatch in multibib_re.finditer(content): + if Verbose: + print("multibib match ",multibibmatch.group(1)) + if multibibmatch is not None: + baselist = multibibmatch.group(1).split(',') + if Verbose: + print("multibib list ", baselist) + for i in range(len(baselist)): + file_list.append(os.path.join(targetdir, baselist[i])) + # now define the side effects + for file_name in file_list: + for suffix in suffix_list[:-1]: + env.SideEffect(file_name + suffix,target[0]) + if Verbose: + print("side effect tst :",file_name + suffix, " target is ",str(target[0])) + env.Clean(target[0],file_name + suffix) + + for aFile in aux_files: + aFile_base = SCons.Util.splitext(aFile)[0] + env.SideEffect(aFile_base + '.aux',target[0]) + if Verbose: + print("side effect aux :",aFile_base + '.aux') + env.Clean(target[0],aFile_base + '.aux') + # read fls file to get all other files that latex creates and will read on the next pass + # remove files from list that we explicitly dealt with above + if os.path.isfile(flsfilename): + with open(flsfilename, "r") as f: + content = f.read() + out_files = openout_re.findall(content) + myfiles = [auxfilename, logfilename, flsfilename, targetbase+'.dvi',targetbase+'.pdf'] + for filename in out_files[:]: + if filename in myfiles: + out_files.remove(filename) + env.SideEffect(out_files,target[0]) + if Verbose: + print("side effect fls :",out_files) + env.Clean(target[0],out_files) + + return (target, source) + + +TeXLaTeXAction = None + +def generate(env): + """Add Builders and construction variables for TeX to an Environment.""" + + global TeXLaTeXAction + if TeXLaTeXAction is None: + TeXLaTeXAction = SCons.Action.Action(TeXLaTeXFunction, + strfunction=TeXLaTeXStrFunction) + + env.AppendUnique(LATEXSUFFIXES=SCons.Tool.LaTeXSuffixes) + + generate_common(env) + + from . import dvi + dvi.generate(env) + + bld = env['BUILDERS']['DVI'] + bld.add_action('.tex', TeXLaTeXAction) + bld.add_emitter('.tex', tex_eps_emitter) + +def generate_darwin(env): + try: + environ = env['ENV'] + except KeyError: + environ = {} + env['ENV'] = environ + + if (platform.system() == 'Darwin'): + try: + ospath = env['ENV']['PATHOSX'] + except: + ospath = None + if ospath: + env.AppendENVPath('PATH', ospath) + +def generate_common(env): + """Add internal Builders and construction variables for LaTeX to an Environment.""" + + # Add OSX system paths so TeX tools can be found + # when a list of tools is given the exists() method is not called + generate_darwin(env) + + # A generic tex file Action, sufficient for all tex files. + global TeXAction + if TeXAction is None: + TeXAction = SCons.Action.Action("$TEXCOM", "$TEXCOMSTR") + + # An Action to build a latex file. This might be needed more + # than once if we are dealing with labels and bibtex. + global LaTeXAction + if LaTeXAction is None: + LaTeXAction = SCons.Action.Action("$LATEXCOM", "$LATEXCOMSTR") + + # Define an action to run BibTeX on a file. + global BibTeXAction + if BibTeXAction is None: + BibTeXAction = SCons.Action.Action("$BIBTEXCOM", "$BIBTEXCOMSTR") + + # Define an action to run Biber on a file. + global BiberAction + if BiberAction is None: + BiberAction = SCons.Action.Action("$BIBERCOM", "$BIBERCOMSTR") + + # Define an action to run MakeIndex on a file. + global MakeIndexAction + if MakeIndexAction is None: + MakeIndexAction = SCons.Action.Action("$MAKEINDEXCOM", "$MAKEINDEXCOMSTR") + + # Define an action to run MakeIndex on a file for nomenclatures. + global MakeNclAction + if MakeNclAction is None: + MakeNclAction = SCons.Action.Action("$MAKENCLCOM", "$MAKENCLCOMSTR") + + # Define an action to run MakeIndex on a file for glossaries. + global MakeGlossaryAction + if MakeGlossaryAction is None: + MakeGlossaryAction = SCons.Action.Action("$MAKEGLOSSARYCOM", "$MAKEGLOSSARYCOMSTR") + + # Define an action to run MakeIndex on a file for acronyms. + global MakeAcronymsAction + if MakeAcronymsAction is None: + MakeAcronymsAction = SCons.Action.Action("$MAKEACRONYMSCOM", "$MAKEACRONYMSCOMSTR") + + try: + environ = env['ENV'] + except KeyError: + environ = {} + env['ENV'] = environ + + # Some Linux platforms have pdflatex set up in a way + # that requires that the HOME environment variable be set. + # Add it here if defined. + v = os.environ.get('HOME') + if v: + environ['HOME'] = v + + CDCOM = 'cd ' + if platform.system() == 'Windows': + # allow cd command to change drives on Windows + CDCOM = 'cd /D ' + + env['TEX'] = 'tex' + env['TEXFLAGS'] = SCons.Util.CLVar('-interaction=nonstopmode -recorder') + env['TEXCOM'] = CDCOM + '${TARGET.dir} && $TEX $TEXFLAGS ${SOURCE.file}' + + env['PDFTEX'] = 'pdftex' + env['PDFTEXFLAGS'] = SCons.Util.CLVar('-interaction=nonstopmode -recorder') + env['PDFTEXCOM'] = CDCOM + '${TARGET.dir} && $PDFTEX $PDFTEXFLAGS ${SOURCE.file}' + + env['LATEX'] = 'latex' + env['LATEXFLAGS'] = SCons.Util.CLVar('-interaction=nonstopmode -recorder') + env['LATEXCOM'] = CDCOM + '${TARGET.dir} && $LATEX $LATEXFLAGS ${SOURCE.file}' + env['LATEXRETRIES'] = 4 + + env['PDFLATEX'] = 'pdflatex' + env['PDFLATEXFLAGS'] = SCons.Util.CLVar('-interaction=nonstopmode -recorder') + env['PDFLATEXCOM'] = CDCOM + '${TARGET.dir} && $PDFLATEX $PDFLATEXFLAGS ${SOURCE.file}' + + env['BIBTEX'] = 'bibtex' + env['BIBTEXFLAGS'] = SCons.Util.CLVar('') + env['BIBTEXCOM'] = CDCOM + '${TARGET.dir} && $BIBTEX $BIBTEXFLAGS ${SOURCE.filebase}' + + env['BIBER'] = 'biber' + env['BIBERFLAGS'] = SCons.Util.CLVar('') + env['BIBERCOM'] = CDCOM + '${TARGET.dir} && $BIBER $BIBERFLAGS ${SOURCE.filebase}' + + env['MAKEINDEX'] = 'makeindex' + env['MAKEINDEXFLAGS'] = SCons.Util.CLVar('') + env['MAKEINDEXCOM'] = CDCOM + '${TARGET.dir} && $MAKEINDEX $MAKEINDEXFLAGS ${SOURCE.file}' + + env['MAKEGLOSSARY'] = 'makeindex' + env['MAKEGLOSSARYSTYLE'] = '${SOURCE.filebase}.ist' + env['MAKEGLOSSARYFLAGS'] = SCons.Util.CLVar('-s ${MAKEGLOSSARYSTYLE} -t ${SOURCE.filebase}.glg') + env['MAKEGLOSSARYCOM'] = CDCOM + '${TARGET.dir} && $MAKEGLOSSARY ${SOURCE.filebase}.glo $MAKEGLOSSARYFLAGS -o ${SOURCE.filebase}.gls' + + env['MAKEACRONYMS'] = 'makeindex' + env['MAKEACRONYMSSTYLE'] = '${SOURCE.filebase}.ist' + env['MAKEACRONYMSFLAGS'] = SCons.Util.CLVar('-s ${MAKEACRONYMSSTYLE} -t ${SOURCE.filebase}.alg') + env['MAKEACRONYMSCOM'] = CDCOM + '${TARGET.dir} && $MAKEACRONYMS ${SOURCE.filebase}.acn $MAKEACRONYMSFLAGS -o ${SOURCE.filebase}.acr' + + env['MAKENCL'] = 'makeindex' + env['MAKENCLSTYLE'] = 'nomencl.ist' + env['MAKENCLFLAGS'] = '-s ${MAKENCLSTYLE} -t ${SOURCE.filebase}.nlg' + env['MAKENCLCOM'] = CDCOM + '${TARGET.dir} && $MAKENCL ${SOURCE.filebase}.nlo $MAKENCLFLAGS -o ${SOURCE.filebase}.nls' + + env['MAKENEWGLOSSARY'] = 'makeindex' + env['MAKENEWGLOSSARYCOM'] = CDCOM + '${TARGET.dir} && $MAKENEWGLOSSARY ' + +def exists(env): + generate_darwin(env) + return env.Detect('tex') + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/textfile.py b/tools/scons/scons-local-3.0.5/SCons/Tool/textfile.py new file mode 100755 index 0000000000..2cfa90618f --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/textfile.py @@ -0,0 +1,208 @@ +# -*- python -*- +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__doc__ = """ +Textfile/Substfile builder for SCons. + + Create file 'target' which typically is a textfile. The 'source' + may be any combination of strings, Nodes, or lists of same. A + 'linesep' will be put between any part written and defaults to + os.linesep. + + The only difference between the Textfile builder and the Substfile + builder is that strings are converted to Value() nodes for the + former and File() nodes for the latter. To insert files in the + former or strings in the latter, wrap them in a File() or Value(), + respectively. + + The values of SUBST_DICT first have any construction variables + expanded (its keys are not expanded). If a value of SUBST_DICT is + a python callable function, it is called and the result is expanded + as the value. Values are substituted in a "random" order; if any + substitution could be further expanded by another substitution, it + is unpredictable whether the expansion will occur. +""" + +__revision__ = "src/engine/SCons/Tool/textfile.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons + +import os +import re + +from SCons.Node import Node +from SCons.Node.Python import Value +from SCons.Util import is_String, is_Sequence, is_Dict, to_bytes, PY3 + + +if PY3: + TEXTFILE_FILE_WRITE_MODE = 'w' +else: + TEXTFILE_FILE_WRITE_MODE = 'wb' + +LINESEP = '\n' + +def _do_subst(node, subs): + """ + Fetch the node contents and replace all instances of the keys with + their values. For example, if subs is + {'%VERSION%': '1.2345', '%BASE%': 'MyProg', '%prefix%': '/bin'}, + then all instances of %VERSION% in the file will be replaced with + 1.2345 and so forth. + """ + contents = node.get_text_contents() + if subs: + for (k, val) in subs: + contents = re.sub(k, val, contents) + + if 'b' in TEXTFILE_FILE_WRITE_MODE: + try: + contents = bytearray(contents, 'utf-8') + except UnicodeDecodeError: + # contents is already utf-8 encoded python 2 str i.e. a byte array + contents = bytearray(contents) + + return contents + + +def _action(target, source, env): + + # prepare the line separator + linesep = env['LINESEPARATOR'] + if linesep is None: + linesep = LINESEP # os.linesep + elif is_String(linesep): + pass + elif isinstance(linesep, Value): + linesep = linesep.get_text_contents() + else: + raise SCons.Errors.UserError('unexpected type/class for LINESEPARATOR: %s' + % repr(linesep), None) + + if 'b' in TEXTFILE_FILE_WRITE_MODE: + linesep = to_bytes(linesep) + + # create a dictionary to use for the substitutions + if 'SUBST_DICT' not in env: + subs = None # no substitutions + else: + subst_dict = env['SUBST_DICT'] + if is_Dict(subst_dict): + subst_dict = list(subst_dict.items()) + elif is_Sequence(subst_dict): + pass + else: + raise SCons.Errors.UserError('SUBST_DICT must be dict or sequence') + subs = [] + for (k, value) in subst_dict: + if callable(value): + value = value() + if is_String(value): + value = env.subst(value) + else: + value = str(value) + subs.append((k, value)) + + # write the file + try: + if SCons.Util.PY3: + target_file = open(target[0].get_path(), TEXTFILE_FILE_WRITE_MODE, newline='') + else: + target_file = open(target[0].get_path(), TEXTFILE_FILE_WRITE_MODE) + except (OSError, IOError): + raise SCons.Errors.UserError("Can't write target file %s" % target[0]) + + # separate lines by 'linesep' only if linesep is not empty + lsep = None + for line in source: + if lsep: + target_file.write(lsep) + + target_file.write(_do_subst(line, subs)) + lsep = linesep + target_file.close() + + +def _strfunc(target, source, env): + return "Creating '%s'" % target[0] + + +def _convert_list_R(newlist, sources): + for elem in sources: + if is_Sequence(elem): + _convert_list_R(newlist, elem) + elif isinstance(elem, Node): + newlist.append(elem) + else: + newlist.append(Value(elem)) + + +def _convert_list(target, source, env): + if len(target) != 1: + raise SCons.Errors.UserError("Only one target file allowed") + newlist = [] + _convert_list_R(newlist, source) + return target, newlist + + +_common_varlist = ['SUBST_DICT', 'LINESEPARATOR'] + +_text_varlist = _common_varlist + ['TEXTFILEPREFIX', 'TEXTFILESUFFIX'] +_text_builder = SCons.Builder.Builder( + action=SCons.Action.Action(_action, _strfunc, varlist=_text_varlist), + source_factory=Value, + emitter=_convert_list, + prefix='$TEXTFILEPREFIX', + suffix='$TEXTFILESUFFIX', +) + +_subst_varlist = _common_varlist + ['SUBSTFILEPREFIX', 'TEXTFILESUFFIX'] +_subst_builder = SCons.Builder.Builder( + action=SCons.Action.Action(_action, _strfunc, varlist=_subst_varlist), + source_factory=SCons.Node.FS.File, + emitter=_convert_list, + prefix='$SUBSTFILEPREFIX', + suffix='$SUBSTFILESUFFIX', + src_suffix=['.in'], +) + + +def generate(env): + env['LINESEPARATOR'] = LINESEP # os.linesep + env['BUILDERS']['Textfile'] = _text_builder + env['TEXTFILEPREFIX'] = '' + env['TEXTFILESUFFIX'] = '.txt' + env['BUILDERS']['Substfile'] = _subst_builder + env['SUBSTFILEPREFIX'] = '' + env['SUBSTFILESUFFIX'] = '' + + +def exists(env): + return 1 + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/tlib.py b/tools/scons/scons-local-3.0.5/SCons/Tool/tlib.py new file mode 100755 index 0000000000..70dd18ac28 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/tlib.py @@ -0,0 +1,53 @@ +"""SCons.Tool.tlib + +XXX + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/tlib.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Tool +import SCons.Tool.bcc32 +import SCons.Util + +def generate(env): + SCons.Tool.bcc32.findIt('tlib', env) + """Add Builders and construction variables for ar to an Environment.""" + SCons.Tool.createStaticLibBuilder(env) + env['AR'] = 'tlib' + env['ARFLAGS'] = SCons.Util.CLVar('') + env['ARCOM'] = '$AR $TARGET $ARFLAGS /a $SOURCES' + env['LIBPREFIX'] = '' + env['LIBSUFFIX'] = '.lib' + +def exists(env): + return SCons.Tool.bcc32.findIt('tlib', env) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/wix.py b/tools/scons/scons-local-3.0.5/SCons/Tool/wix.py new file mode 100755 index 0000000000..b4f63ad5fb --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/wix.py @@ -0,0 +1,104 @@ +"""SCons.Tool.wix + +Tool-specific initialization for wix, the Windows Installer XML Tool. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/wix.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import SCons.Builder +import SCons.Action +import os + +def generate(env): + """Add Builders and construction variables for WiX to an Environment.""" + if not exists(env): + return + + env['WIXCANDLEFLAGS'] = ['-nologo'] + env['WIXCANDLEINCLUDE'] = [] + env['WIXCANDLECOM'] = '$WIXCANDLE $WIXCANDLEFLAGS -I $WIXCANDLEINCLUDE -o ${TARGET} ${SOURCE}' + + env['WIXLIGHTFLAGS'].append( '-nologo' ) + env['WIXLIGHTCOM'] = "$WIXLIGHT $WIXLIGHTFLAGS -out ${TARGET} ${SOURCES}" + env['WIXSRCSUF'] = '.wxs' + env['WIXOBJSUF'] = '.wixobj' + + object_builder = SCons.Builder.Builder( + action = '$WIXCANDLECOM', + suffix = '$WIXOBJSUF', + src_suffix = '$WIXSRCSUF') + + linker_builder = SCons.Builder.Builder( + action = '$WIXLIGHTCOM', + src_suffix = '$WIXOBJSUF', + src_builder = object_builder) + + env['BUILDERS']['WiX'] = linker_builder + +def exists(env): + env['WIXCANDLE'] = 'candle.exe' + env['WIXLIGHT'] = 'light.exe' + + # try to find the candle.exe and light.exe tools and + # add the install directory to light libpath. + for path in os.environ['PATH'].split(os.pathsep): + if not path: + continue + + # workaround for some weird python win32 bug. + if path[0] == '"' and path[-1:]=='"': + path = path[1:-1] + + # normalize the path + path = os.path.normpath(path) + + # search for the tools in the PATH environment variable + try: + files = os.listdir(path) + if env['WIXCANDLE'] in files and env['WIXLIGHT'] in files: + env.PrependENVPath('PATH', path) + # include appropriate flags if running WiX 2.0 + if 'wixui.wixlib' in files and 'WixUI_en-us.wxl' in files: + env['WIXLIGHTFLAGS'] = [ os.path.join( path, 'wixui.wixlib' ), + '-loc', + os.path.join( path, 'WixUI_en-us.wxl' ) ] + else: + env['WIXLIGHTFLAGS'] = [] + return 1 + except OSError: + pass # ignore this, could be a stale PATH entry. + + return None + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/xgettext.py b/tools/scons/scons-local-3.0.5/SCons/Tool/xgettext.py new file mode 100755 index 0000000000..8925a9dc18 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/xgettext.py @@ -0,0 +1,374 @@ +""" xgettext tool + +Tool specific initialization of `xgettext` tool. +""" + +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +__revision__ = "src/engine/SCons/Tool/xgettext.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + + +############################################################################# +class _CmdRunner(object): + """ Callable object, which runs shell command storing its stdout and stderr to + variables. It also provides `strfunction()` method, which shall be used by + scons Action objects to print command string. """ + + def __init__(self, command, commandstr=None): + self.out = None + self.err = None + self.status = None + self.command = command + self.commandstr = commandstr + + def __call__(self, target, source, env): + import SCons.Action + import subprocess + import os + import sys + kw = { + 'stdin': 'devnull', + 'stdout': subprocess.PIPE, + 'stderr': subprocess.PIPE, + 'universal_newlines': True, + 'shell': True + } + command = env.subst(self.command, target=target, source=source) + proc = SCons.Action._subproc(env, command, **kw) + self.out, self.err = proc.communicate() + self.status = proc.wait() + if self.err: + sys.stderr.write(unicode(self.err)) + return self.status + + def strfunction(self, target, source, env): + import os + comstr = self.commandstr + if env.subst(comstr, target=target, source=source) == "": + comstr = self.command + s = env.subst(comstr, target=target, source=source) + return s + + +############################################################################# + +############################################################################# +def _update_pot_file(target, source, env): + """ Action function for `POTUpdate` builder """ + import re + import os + import SCons.Action + nop = lambda target, source, env: 0 + + # Save scons cwd and os cwd (NOTE: they may be different. After the job, we + # revert each one to its original state). + save_cwd = env.fs.getcwd() + save_os_cwd = os.getcwd() + chdir = target[0].dir + chdir_str = repr(chdir.get_abspath()) + # Print chdir message (employ SCons.Action.Action for that. It knows better + # than me how to to this correctly). + env.Execute(SCons.Action.Action(nop, "Entering " + chdir_str)) + # Go to target's directory and do our job + env.fs.chdir(chdir, 1) # Go into target's directory + try: + cmd = _CmdRunner('$XGETTEXTCOM', '$XGETTEXTCOMSTR') + action = SCons.Action.Action(cmd, strfunction=cmd.strfunction) + status = action([target[0]], source, env) + except: + # Something went wrong. + env.Execute(SCons.Action.Action(nop, "Leaving " + chdir_str)) + # Revert working dirs to previous state and re-throw exception. + env.fs.chdir(save_cwd, 0) + os.chdir(save_os_cwd) + raise + # Print chdir message. + env.Execute(SCons.Action.Action(nop, "Leaving " + chdir_str)) + # Revert working dirs to previous state. + env.fs.chdir(save_cwd, 0) + os.chdir(save_os_cwd) + # If the command was not successfull, return error code. + if status: return status + + new_content = cmd.out + + if not new_content: + # When xgettext finds no internationalized messages, no *.pot is created + # (because we don't want to bother translators with empty POT files). + needs_update = False + explain = "no internationalized messages encountered" + else: + if target[0].exists(): + # If the file already exists, it's left unaltered unless its messages + # are outdated (w.r.t. to these recovered by xgettext from sources). + old_content = target[0].get_text_contents() + re_cdate = re.compile(r'^"POT-Creation-Date: .*"$[\r\n]?', re.M) + old_content_nocdate = re.sub(re_cdate, "", old_content) + new_content_nocdate = re.sub(re_cdate, "", new_content) + if (old_content_nocdate == new_content_nocdate): + # Messages are up-to-date + needs_update = False + explain = "messages in file found to be up-to-date" + else: + # Messages are outdated + needs_update = True + explain = "messages in file were outdated" + else: + # No POT file found, create new one + needs_update = True + explain = "new file" + if needs_update: + # Print message employing SCons.Action.Action for that. + msg = "Writing " + repr(str(target[0])) + " (" + explain + ")" + env.Execute(SCons.Action.Action(nop, msg)) + f = open(str(target[0]), "w") + f.write(new_content) + f.close() + return 0 + else: + # Print message employing SCons.Action.Action for that. + msg = "Not writing " + repr(str(target[0])) + " (" + explain + ")" + env.Execute(SCons.Action.Action(nop, msg)) + return 0 + + +############################################################################# + +############################################################################# +from SCons.Builder import BuilderBase + + +############################################################################# +class _POTBuilder(BuilderBase): + def _execute(self, env, target, source, *args): + if not target: + if 'POTDOMAIN' in env and env['POTDOMAIN']: + domain = env['POTDOMAIN'] + else: + domain = 'messages' + target = [domain] + return BuilderBase._execute(self, env, target, source, *args) + + +############################################################################# + +############################################################################# +def _scan_xgettext_from_files(target, source, env, files=None, path=None): + """ Parses `POTFILES.in`-like file and returns list of extracted file names. + """ + import re + import SCons.Util + import SCons.Node.FS + + if files is None: + return 0 + if not SCons.Util.is_List(files): + files = [files] + + if path is None: + if 'XGETTEXTPATH' in env: + path = env['XGETTEXTPATH'] + else: + path = [] + if not SCons.Util.is_List(path): + path = [path] + + path = SCons.Util.flatten(path) + + dirs = () + for p in path: + if not isinstance(p, SCons.Node.FS.Base): + if SCons.Util.is_String(p): + p = env.subst(p, source=source, target=target) + p = env.arg2nodes(p, env.fs.Dir) + dirs += tuple(p) + # cwd is the default search path (when no path is defined by user) + if not dirs: + dirs = (env.fs.getcwd(),) + + # Parse 'POTFILE.in' files. + re_comment = re.compile(r'^#[^\n\r]*$\r?\n?', re.M) + re_emptyln = re.compile(r'^[ \t\r]*$\r?\n?', re.M) + re_trailws = re.compile(r'[ \t\r]+$') + for f in files: + # Find files in search path $XGETTEXTPATH + if isinstance(f, SCons.Node.FS.Base) and f.rexists(): + contents = f.get_text_contents() + contents = re_comment.sub("", contents) + contents = re_emptyln.sub("", contents) + contents = re_trailws.sub("", contents) + depnames = contents.splitlines() + for depname in depnames: + depfile = SCons.Node.FS.find_file(depname, dirs) + if not depfile: + depfile = env.arg2nodes(depname, dirs[0].File) + env.Depends(target, depfile) + return 0 + + +############################################################################# + +############################################################################# +def _pot_update_emitter(target, source, env): + """ Emitter function for `POTUpdate` builder """ + from SCons.Tool.GettextCommon import _POTargetFactory + import SCons.Util + import SCons.Node.FS + + if 'XGETTEXTFROM' in env: + xfrom = env['XGETTEXTFROM'] + else: + return target, source + if not SCons.Util.is_List(xfrom): + xfrom = [xfrom] + + xfrom = SCons.Util.flatten(xfrom) + + # Prepare list of 'POTFILE.in' files. + files = [] + for xf in xfrom: + if not isinstance(xf, SCons.Node.FS.Base): + if SCons.Util.is_String(xf): + # Interpolate variables in strings + xf = env.subst(xf, source=source, target=target) + xf = env.arg2nodes(xf) + files.extend(xf) + if files: + env.Depends(target, files) + _scan_xgettext_from_files(target, source, env, files) + return target, source + + +############################################################################# + +############################################################################# +from SCons.Environment import _null + + +############################################################################# +def _POTUpdateBuilderWrapper(env, target=None, source=_null, **kw): + return env._POTUpdateBuilder(target, source, **kw) + + +############################################################################# + +############################################################################# +def _POTUpdateBuilder(env, **kw): + """ Creates `POTUpdate` builder object """ + import SCons.Action + from SCons.Tool.GettextCommon import _POTargetFactory + kw['action'] = SCons.Action.Action(_update_pot_file, None) + kw['suffix'] = '$POTSUFFIX' + kw['target_factory'] = _POTargetFactory(env, alias='$POTUPDATE_ALIAS').File + kw['emitter'] = _pot_update_emitter + return _POTBuilder(**kw) + + +############################################################################# + +############################################################################# +def generate(env, **kw): + """ Generate `xgettext` tool """ + import sys + import os + import SCons.Util + import SCons.Tool + from SCons.Tool.GettextCommon import RPaths, _detect_xgettext + from SCons.Platform.mingw import MINGW_DEFAULT_PATHS + from SCons.Platform.cygwin import CYGWIN_DEFAULT_PATHS + + if sys.platform == 'win32': + xgettext = SCons.Tool.find_program_path(env, 'xgettext', default_paths=MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS ) + if xgettext: + xgettext_bin_dir = os.path.dirname(xgettext) + env.AppendENVPath('PATH', xgettext_bin_dir) + else: + SCons.Warnings.Warning('xgettext tool requested, but binary not found in ENV PATH') + try: + env['XGETTEXT'] = _detect_xgettext(env) + except: + env['XGETTEXT'] = 'xgettext' + # NOTE: sources="$SOURCES" would work as well. However, we use following + # construction to convert absolute paths provided by scons onto paths + # relative to current working dir. Note, that scons expands $SOURCE(S) to + # absolute paths for sources $SOURCE(s) outside of current subtree (e.g. in + # "../"). With source=$SOURCE these absolute paths would be written to the + # resultant *.pot file (and its derived *.po files) as references to lines in + # source code (e.g. referring lines in *.c files). Such references would be + # correct (e.g. in poedit) only on machine on which *.pot was generated and + # would be of no use on other hosts (having a copy of source code located + # in different place in filesystem). + sources = '$( ${_concat( "", SOURCES, "", __env__, XgettextRPaths, TARGET' \ + + ', SOURCES)} $)' + + # NOTE: the output from $XGETTEXTCOM command must go to stdout, not to a file. + # This is required by the POTUpdate builder's action. + xgettextcom = '$XGETTEXT $XGETTEXTFLAGS $_XGETTEXTPATHFLAGS' \ + + ' $_XGETTEXTFROMFLAGS -o - ' + sources + + xgettextpathflags = '$( ${_concat( XGETTEXTPATHPREFIX, XGETTEXTPATH' \ + + ', XGETTEXTPATHSUFFIX, __env__, RDirs, TARGET, SOURCES)} $)' + xgettextfromflags = '$( ${_concat( XGETTEXTFROMPREFIX, XGETTEXTFROM' \ + + ', XGETTEXTFROMSUFFIX, __env__, target=TARGET, source=SOURCES)} $)' + + env.SetDefault( + _XGETTEXTDOMAIN='${TARGET.filebase}', + XGETTEXTFLAGS=[], + XGETTEXTCOM=xgettextcom, + XGETTEXTCOMSTR='', + XGETTEXTPATH=[], + XGETTEXTPATHPREFIX='-D', + XGETTEXTPATHSUFFIX='', + XGETTEXTFROM=None, + XGETTEXTFROMPREFIX='-f', + XGETTEXTFROMSUFFIX='', + _XGETTEXTPATHFLAGS=xgettextpathflags, + _XGETTEXTFROMFLAGS=xgettextfromflags, + POTSUFFIX=['.pot'], + POTUPDATE_ALIAS='pot-update', + XgettextRPaths=RPaths(env) + ) + env.Append(BUILDERS={ + '_POTUpdateBuilder': _POTUpdateBuilder(env) + }) + env.AddMethod(_POTUpdateBuilderWrapper, 'POTUpdate') + env.AlwaysBuild(env.Alias('$POTUPDATE_ALIAS')) + + +############################################################################# + +############################################################################# +def exists(env): + """ Check, whether the tool exists """ + from SCons.Tool.GettextCommon import _xgettext_exists + try: + return _xgettext_exists(env) + except: + return False + +############################################################################# + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/yacc.py b/tools/scons/scons-local-3.0.5/SCons/Tool/yacc.py new file mode 100755 index 0000000000..d328d20524 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/yacc.py @@ -0,0 +1,171 @@ +"""SCons.Tool.yacc + +Tool-specific initialization for yacc. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/yacc.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os.path +import sys + +import SCons.Defaults +import SCons.Tool +import SCons.Util +from SCons.Platform.mingw import MINGW_DEFAULT_PATHS +from SCons.Platform.cygwin import CYGWIN_DEFAULT_PATHS +from SCons.Platform.win32 import CHOCO_DEFAULT_PATH + +YaccAction = SCons.Action.Action("$YACCCOM", "$YACCCOMSTR") + +def _yaccEmitter(target, source, env, ysuf, hsuf): + yaccflags = env.subst("$YACCFLAGS", target=target, source=source) + flags = SCons.Util.CLVar(yaccflags) + targetBase, targetExt = os.path.splitext(SCons.Util.to_String(target[0])) + + if '.ym' in ysuf: # If using Objective-C + target = [targetBase + ".m"] # the extension is ".m". + + + # If -d is specified on the command line, yacc will emit a .h + # or .hpp file with the same name as the .c or .cpp output file. + if '-d' in flags: + target.append(targetBase + env.subst(hsuf, target=target, source=source)) + + # If -g is specified on the command line, yacc will emit a .vcg + # file with the same base name as the .y, .yacc, .ym or .yy file. + if "-g" in flags: + base, ext = os.path.splitext(SCons.Util.to_String(source[0])) + target.append(base + env.subst("$YACCVCGFILESUFFIX")) + + # If -v is specified yacc will create the output debug file + # which is not really source for any process, but should + # be noted and also be cleaned + # Bug #2558 + if "-v" in flags: + env.SideEffect(targetBase+'.output',target[0]) + env.Clean(target[0],targetBase+'.output') + + + + # With --defines and --graph, the name of the file is totally defined + # in the options. + fileGenOptions = ["--defines=", "--graph="] + for option in flags: + for fileGenOption in fileGenOptions: + l = len(fileGenOption) + if option[:l] == fileGenOption: + # A file generating option is present, so add the file + # name to the list of targets. + fileName = option[l:].strip() + target.append(fileName) + + return (target, source) + +def yEmitter(target, source, env): + return _yaccEmitter(target, source, env, ['.y', '.yacc'], '$YACCHFILESUFFIX') + +def ymEmitter(target, source, env): + return _yaccEmitter(target, source, env, ['.ym'], '$YACCHFILESUFFIX') + +def yyEmitter(target, source, env): + return _yaccEmitter(target, source, env, ['.yy'], '$YACCHXXFILESUFFIX') + +def get_yacc_path(env, append_paths=False): + """ + Find the a path containing the lex or flex binaries. If a construction + environment is passed in then append the path to the ENV PATH. + """ + # save existing path to reset if we don't want to append any paths + envPath = env['ENV']['PATH'] + bins = ['bison', 'yacc', 'win_bison'] + + for prog in bins: + bin_path = SCons.Tool.find_program_path( + env, + prog, + default_paths=CHOCO_DEFAULT_PATH + MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS ) + if bin_path: + if not append_paths: + env['ENV']['PATH'] = envPath + else: + env.AppendENVPath('PATH', os.path.dirname(bin_path)) + return bin_path + SCons.Warnings.Warning('lex tool requested, but lex or flex binary not found in ENV PATH') + +def generate(env): + """Add Builders and construction variables for yacc to an Environment.""" + c_file, cxx_file = SCons.Tool.createCFileBuilders(env) + + # C + c_file.add_action('.y', YaccAction) + c_file.add_emitter('.y', yEmitter) + + c_file.add_action('.yacc', YaccAction) + c_file.add_emitter('.yacc', yEmitter) + + # Objective-C + c_file.add_action('.ym', YaccAction) + c_file.add_emitter('.ym', ymEmitter) + + # C++ + cxx_file.add_action('.yy', YaccAction) + cxx_file.add_emitter('.yy', yyEmitter) + + if sys.platform == 'win32': + bison = SCons.Tool.find_program_path(env, 'bison', default_paths=MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS ) + if bison: + bison_bin_dir = os.path.dirname(bison) + env.AppendENVPath('PATH', bison_bin_dir) + else: + SCons.Warnings.Warning('yacc tool requested, but bison binary not found in ENV PATH') + + if sys.platform == 'win32': + get_yacc_path(env, append_paths=True) + env["YACC"] = env.Detect(['bison', 'yacc', 'win_bison']) + else: + env["YACC"] = env.Detect(["bison", "yacc"]) + + env['YACCFLAGS'] = SCons.Util.CLVar('') + env['YACCCOM'] = '$YACC $YACCFLAGS -o $TARGET $SOURCES' + env['YACCHFILESUFFIX'] = '.h' + + env['YACCHXXFILESUFFIX'] = '.hpp' + + env['YACCVCGFILESUFFIX'] = '.vcg' + +def exists(env): + return env.Detect(['bison', 'yacc']) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Tool/zip.py b/tools/scons/scons-local-3.0.5/SCons/Tool/zip.py new file mode 100755 index 0000000000..2689634b49 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Tool/zip.py @@ -0,0 +1,92 @@ +"""SCons.Tool.zip + +Tool-specific initialization for zip. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/zip.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os.path + +import SCons.Builder +import SCons.Defaults +import SCons.Node.FS +import SCons.Util + +import zipfile + +zipcompression = zipfile.ZIP_DEFLATED +def zip(target, source, env): + compression = env.get('ZIPCOMPRESSION', 0) + zf = zipfile.ZipFile(str(target[0]), 'w', compression) + for s in source: + if s.isdir(): + for dirpath, dirnames, filenames in os.walk(str(s)): + for fname in filenames: + path = os.path.join(dirpath, fname) + if os.path.isfile(path): + + zf.write(path, os.path.relpath(path, str(env.get('ZIPROOT', '')))) + else: + zf.write(str(s), os.path.relpath(str(s), str(env.get('ZIPROOT', '')))) + zf.close() + +zipAction = SCons.Action.Action(zip, varlist=['ZIPCOMPRESSION']) + +ZipBuilder = SCons.Builder.Builder(action = SCons.Action.Action('$ZIPCOM', '$ZIPCOMSTR'), + source_factory = SCons.Node.FS.Entry, + source_scanner = SCons.Defaults.DirScanner, + suffix = '$ZIPSUFFIX', + multi = 1) + + +def generate(env): + """Add Builders and construction variables for zip to an Environment.""" + try: + bld = env['BUILDERS']['Zip'] + except KeyError: + bld = ZipBuilder + env['BUILDERS']['Zip'] = bld + + env['ZIP'] = 'zip' + env['ZIPFLAGS'] = SCons.Util.CLVar('') + env['ZIPCOM'] = zipAction + env['ZIPCOMPRESSION'] = zipcompression + env['ZIPSUFFIX'] = '.zip' + env['ZIPROOT'] = SCons.Util.CLVar('') + +def exists(env): + return True + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Util.py b/tools/scons/scons-local-3.0.5/SCons/Util.py new file mode 100755 index 0000000000..476f5d8445 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Util.py @@ -0,0 +1,1635 @@ +"""SCons.Util + +Various utility functions go here. +""" +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +__revision__ = "src/engine/SCons/Util.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os +import sys +import copy +import re +import types +import codecs +import pprint + +PY3 = sys.version_info[0] == 3 + +try: + from collections import UserDict, UserList, UserString +except ImportError: + from UserDict import UserDict + from UserList import UserList + from UserString import UserString + +try: + from collections.abc import Iterable, MappingView +except ImportError: + from collections import Iterable + +from collections import OrderedDict + +# Don't "from types import ..." these because we need to get at the +# types module later to look for UnicodeType. + +# Below not used? +# InstanceType = types.InstanceType + +MethodType = types.MethodType +FunctionType = types.FunctionType + +try: + _ = type(unicode) +except NameError: + UnicodeType = str +else: + UnicodeType = unicode + +def dictify(keys, values, result={}): + for k, v in zip(keys, values): + result[k] = v + return result + +_altsep = os.altsep +if _altsep is None and sys.platform == 'win32': + # My ActivePython 2.0.1 doesn't set os.altsep! What gives? + _altsep = '/' +if _altsep: + def rightmost_separator(path, sep): + return max(path.rfind(sep), path.rfind(_altsep)) +else: + def rightmost_separator(path, sep): + return path.rfind(sep) + +# First two from the Python Cookbook, just for completeness. +# (Yeah, yeah, YAGNI...) +def containsAny(str, set): + """Check whether sequence str contains ANY of the items in set.""" + for c in set: + if c in str: return 1 + return 0 + +def containsAll(str, set): + """Check whether sequence str contains ALL of the items in set.""" + for c in set: + if c not in str: return 0 + return 1 + +def containsOnly(str, set): + """Check whether sequence str contains ONLY items in set.""" + for c in str: + if c not in set: return 0 + return 1 + +def splitext(path): + """Same as os.path.splitext() but faster.""" + sep = rightmost_separator(path, os.sep) + dot = path.rfind('.') + # An ext is only real if it has at least one non-digit char + if dot > sep and not containsOnly(path[dot:], "0123456789."): + return path[:dot],path[dot:] + else: + return path,"" + +def updrive(path): + """ + Make the drive letter (if any) upper case. + This is useful because Windows is inconsistent on the case + of the drive letter, which can cause inconsistencies when + calculating command signatures. + """ + drive, rest = os.path.splitdrive(path) + if drive: + path = drive.upper() + rest + return path + +class NodeList(UserList): + """This class is almost exactly like a regular list of Nodes + (actually it can hold any object), with one important difference. + If you try to get an attribute from this list, it will return that + attribute from every item in the list. For example: + + >>> someList = NodeList([ ' foo ', ' bar ' ]) + >>> someList.strip() + [ 'foo', 'bar' ] + """ + +# def __init__(self, initlist=None): +# self.data = [] +# # print("TYPE:%s"%type(initlist)) +# if initlist is not None: +# # XXX should this accept an arbitrary sequence? +# if type(initlist) == type(self.data): +# self.data[:] = initlist +# elif isinstance(initlist, (UserList, NodeList)): +# self.data[:] = initlist.data[:] +# elif isinstance(initlist, Iterable): +# self.data = list(initlist) +# else: +# self.data = [ initlist,] + + + def __nonzero__(self): + return len(self.data) != 0 + + def __bool__(self): + return self.__nonzero__() + + def __str__(self): + return ' '.join(map(str, self.data)) + + def __iter__(self): + return iter(self.data) + + def __call__(self, *args, **kwargs): + result = [x(*args, **kwargs) for x in self.data] + return self.__class__(result) + + def __getattr__(self, name): + result = [getattr(x, name) for x in self.data] + return self.__class__(result) + + def __getitem__(self, index): + """ + This comes for free on py2, + but py3 slices of NodeList are returning a list + breaking slicing nodelist and refering to + properties and methods on contained object + """ +# return self.__class__(self.data[index]) + + if isinstance(index, slice): + # Expand the slice object using range() + # limited by number of items in self.data + indices = index.indices(len(self.data)) + return self.__class__([self[x] for x in + range(*indices)]) + else: + # Return one item of the tart + return self.data[index] + + +_get_env_var = re.compile(r'^\$([_a-zA-Z]\w*|{[_a-zA-Z]\w*})$') + +def get_environment_var(varstr): + """Given a string, first determine if it looks like a reference + to a single environment variable, like "$FOO" or "${FOO}". + If so, return that variable with no decorations ("FOO"). + If not, return None.""" + mo=_get_env_var.match(to_String(varstr)) + if mo: + var = mo.group(1) + if var[0] == '{': + return var[1:-1] + else: + return var + else: + return None + +class DisplayEngine(object): + print_it = True + def __call__(self, text, append_newline=1): + if not self.print_it: + return + if append_newline: text = text + '\n' + try: + sys.stdout.write(UnicodeType(text)) + except IOError: + # Stdout might be connected to a pipe that has been closed + # by now. The most likely reason for the pipe being closed + # is that the user has press ctrl-c. It this is the case, + # then SCons is currently shutdown. We therefore ignore + # IOError's here so that SCons can continue and shutdown + # properly so that the .sconsign is correctly written + # before SCons exits. + pass + + def set_mode(self, mode): + self.print_it = mode + + +def render_tree(root, child_func, prune=0, margin=[0], visited=None): + """ + Render a tree of nodes into an ASCII tree view. + + :Parameters: + - `root`: the root node of the tree + - `child_func`: the function called to get the children of a node + - `prune`: don't visit the same node twice + - `margin`: the format of the left margin to use for children of root. 1 results in a pipe, and 0 results in no pipe. + - `visited`: a dictionary of visited nodes in the current branch if not prune, or in the whole tree if prune. + """ + + rname = str(root) + + # Initialize 'visited' dict, if required + if visited is None: + visited = {} + + children = child_func(root) + retval = "" + for pipe in margin[:-1]: + if pipe: + retval = retval + "| " + else: + retval = retval + " " + + if rname in visited: + return retval + "+-[" + rname + "]\n" + + retval = retval + "+-" + rname + "\n" + if not prune: + visited = copy.copy(visited) + visited[rname] = 1 + + for i in range(len(children)): + margin.append(i < len(children)-1) + retval = retval + render_tree(children[i], child_func, prune, margin, visited) + margin.pop() + + return retval + +IDX = lambda N: N and 1 or 0 + + +def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited=None): + """ + Print a tree of nodes. This is like render_tree, except it prints + lines directly instead of creating a string representation in memory, + so that huge trees can be printed. + + :Parameters: + - `root` - the root node of the tree + - `child_func` - the function called to get the children of a node + - `prune` - don't visit the same node twice + - `showtags` - print status information to the left of each node line + - `margin` - the format of the left margin to use for children of root. 1 results in a pipe, and 0 results in no pipe. + - `visited` - a dictionary of visited nodes in the current branch if not prune, or in the whole tree if prune. + """ + + rname = str(root) + + + # Initialize 'visited' dict, if required + if visited is None: + visited = {} + + if showtags: + + if showtags == 2: + legend = (' E = exists\n' + + ' R = exists in repository only\n' + + ' b = implicit builder\n' + + ' B = explicit builder\n' + + ' S = side effect\n' + + ' P = precious\n' + + ' A = always build\n' + + ' C = current\n' + + ' N = no clean\n' + + ' H = no cache\n' + + '\n') + sys.stdout.write(legend) + + tags = ['['] + tags.append(' E'[IDX(root.exists())]) + tags.append(' R'[IDX(root.rexists() and not root.exists())]) + tags.append(' BbB'[[0,1][IDX(root.has_explicit_builder())] + + [0,2][IDX(root.has_builder())]]) + tags.append(' S'[IDX(root.side_effect)]) + tags.append(' P'[IDX(root.precious)]) + tags.append(' A'[IDX(root.always_build)]) + tags.append(' C'[IDX(root.is_up_to_date())]) + tags.append(' N'[IDX(root.noclean)]) + tags.append(' H'[IDX(root.nocache)]) + tags.append(']') + + else: + tags = [] + + def MMM(m): + return [" ","| "][m] + margins = list(map(MMM, margin[:-1])) + + children = child_func(root) + + if prune and rname in visited and children: + sys.stdout.write(''.join(tags + margins + ['+-[', rname, ']']) + '\n') + return + + sys.stdout.write(''.join(tags + margins + ['+-', rname]) + '\n') + + visited[rname] = 1 + + if children: + margin.append(1) + idx = IDX(showtags) + for C in children[:-1]: + print_tree(C, child_func, prune, idx, margin, visited) + margin[-1] = 0 + print_tree(children[-1], child_func, prune, idx, margin, visited) + margin.pop() + + + +# Functions for deciding if things are like various types, mainly to +# handle UserDict, UserList and UserString like their underlying types. +# +# Yes, all of this manual testing breaks polymorphism, and the real +# Pythonic way to do all of this would be to just try it and handle the +# exception, but handling the exception when it's not the right type is +# often too slow. + +# We are using the following trick to speed up these +# functions. Default arguments are used to take a snapshot of +# the global functions and constants used by these functions. This +# transforms accesses to global variable into local variables +# accesses (i.e. LOAD_FAST instead of LOAD_GLOBAL). + +DictTypes = (dict, UserDict) +ListTypes = (list, UserList) + +try: + # Handle getting dictionary views. + SequenceTypes = (list, tuple, UserList, MappingView) +except NameError: + SequenceTypes = (list, tuple, UserList) + + +# Note that profiling data shows a speed-up when comparing +# explicitly with str and unicode instead of simply comparing +# with basestring. (at least on Python 2.5.1) +try: + StringTypes = (str, unicode, UserString) +except NameError: + StringTypes = (str, UserString) + +# Empirically, it is faster to check explicitly for str and +# unicode than for basestring. +try: + BaseStringTypes = (str, unicode) +except NameError: + BaseStringTypes = (str) + +def is_Dict(obj, isinstance=isinstance, DictTypes=DictTypes): + return isinstance(obj, DictTypes) + +def is_List(obj, isinstance=isinstance, ListTypes=ListTypes): + return isinstance(obj, ListTypes) + +def is_Sequence(obj, isinstance=isinstance, SequenceTypes=SequenceTypes): + return isinstance(obj, SequenceTypes) + +def is_Tuple(obj, isinstance=isinstance, tuple=tuple): + return isinstance(obj, tuple) + +def is_String(obj, isinstance=isinstance, StringTypes=StringTypes): + return isinstance(obj, StringTypes) + +def is_Scalar(obj, isinstance=isinstance, StringTypes=StringTypes, SequenceTypes=SequenceTypes): + # Profiling shows that there is an impressive speed-up of 2x + # when explicitly checking for strings instead of just not + # sequence when the argument (i.e. obj) is already a string. + # But, if obj is a not string then it is twice as fast to + # check only for 'not sequence'. The following code therefore + # assumes that the obj argument is a string most of the time. + return isinstance(obj, StringTypes) or not isinstance(obj, SequenceTypes) + +def do_flatten(sequence, result, isinstance=isinstance, + StringTypes=StringTypes, SequenceTypes=SequenceTypes): + for item in sequence: + if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes): + result.append(item) + else: + do_flatten(item, result) + +def flatten(obj, isinstance=isinstance, StringTypes=StringTypes, + SequenceTypes=SequenceTypes, do_flatten=do_flatten): + """Flatten a sequence to a non-nested list. + + Flatten() converts either a single scalar or a nested sequence + to a non-nested list. Note that flatten() considers strings + to be scalars instead of sequences like Python would. + """ + if isinstance(obj, StringTypes) or not isinstance(obj, SequenceTypes): + return [obj] + result = [] + for item in obj: + if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes): + result.append(item) + else: + do_flatten(item, result) + return result + +def flatten_sequence(sequence, isinstance=isinstance, StringTypes=StringTypes, + SequenceTypes=SequenceTypes, do_flatten=do_flatten): + """Flatten a sequence to a non-nested list. + + Same as flatten(), but it does not handle the single scalar + case. This is slightly more efficient when one knows that + the sequence to flatten can not be a scalar. + """ + result = [] + for item in sequence: + if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes): + result.append(item) + else: + do_flatten(item, result) + return result + +# Generic convert-to-string functions that abstract away whether or +# not the Python we're executing has Unicode support. The wrapper +# to_String_for_signature() will use a for_signature() method if the +# specified object has one. +# +def to_String(s, + isinstance=isinstance, str=str, + UserString=UserString, BaseStringTypes=BaseStringTypes): + if isinstance(s,BaseStringTypes): + # Early out when already a string! + return s + elif isinstance(s, UserString): + # s.data can only be either a unicode or a regular + # string. Please see the UserString initializer. + return s.data + else: + return str(s) + +def to_String_for_subst(s, + isinstance=isinstance, str=str, to_String=to_String, + BaseStringTypes=BaseStringTypes, SequenceTypes=SequenceTypes, + UserString=UserString): + + # Note that the test cases are sorted by order of probability. + if isinstance(s, BaseStringTypes): + return s + elif isinstance(s, SequenceTypes): + return ' '.join([to_String_for_subst(e) for e in s]) + elif isinstance(s, UserString): + # s.data can only be either a unicode or a regular + # string. Please see the UserString initializer. + return s.data + else: + return str(s) + +def to_String_for_signature(obj, to_String_for_subst=to_String_for_subst, + AttributeError=AttributeError): + try: + f = obj.for_signature + except AttributeError: + if isinstance(obj, dict): + # pprint will output dictionary in key sorted order + # with py3.5 the order was randomized. In general depending on dictionary order + # which was undefined until py3.6 (where it's by insertion order) was not wise. + return pprint.pformat(obj, width=1000000) + else: + return to_String_for_subst(obj) + else: + return f() + + +# The SCons "semi-deep" copy. +# +# This makes separate copies of lists (including UserList objects) +# dictionaries (including UserDict objects) and tuples, but just copies +# references to anything else it finds. +# +# A special case is any object that has a __semi_deepcopy__() method, +# which we invoke to create the copy. Currently only used by +# BuilderDict to actually prevent the copy operation (as invalid on that object). +# +# The dispatch table approach used here is a direct rip-off from the +# normal Python copy module. + +_semi_deepcopy_dispatch = d = {} + +def semi_deepcopy_dict(x, exclude = [] ): + copy = {} + for key, val in x.items(): + # The regular Python copy.deepcopy() also deepcopies the key, + # as follows: + # + # copy[semi_deepcopy(key)] = semi_deepcopy(val) + # + # Doesn't seem like we need to, but we'll comment it just in case. + if key not in exclude: + copy[key] = semi_deepcopy(val) + return copy +d[dict] = semi_deepcopy_dict + +def _semi_deepcopy_list(x): + return list(map(semi_deepcopy, x)) +d[list] = _semi_deepcopy_list + +def _semi_deepcopy_tuple(x): + return tuple(map(semi_deepcopy, x)) +d[tuple] = _semi_deepcopy_tuple + +def semi_deepcopy(x): + copier = _semi_deepcopy_dispatch.get(type(x)) + if copier: + return copier(x) + else: + if hasattr(x, '__semi_deepcopy__') and callable(x.__semi_deepcopy__): + return x.__semi_deepcopy__() + elif isinstance(x, UserDict): + return x.__class__(semi_deepcopy_dict(x)) + elif isinstance(x, UserList): + return x.__class__(_semi_deepcopy_list(x)) + + return x + + +class Proxy(object): + """A simple generic Proxy class, forwarding all calls to + subject. So, for the benefit of the python newbie, what does + this really mean? Well, it means that you can take an object, let's + call it 'objA', and wrap it in this Proxy class, with a statement + like this + + proxyObj = Proxy(objA), + + Then, if in the future, you do something like this + + x = proxyObj.var1, + + since Proxy does not have a 'var1' attribute (but presumably objA does), + the request actually is equivalent to saying + + x = objA.var1 + + Inherit from this class to create a Proxy. + + Note that, with new-style classes, this does *not* work transparently + for Proxy subclasses that use special .__*__() method names, because + those names are now bound to the class, not the individual instances. + You now need to know in advance which .__*__() method names you want + to pass on to the underlying Proxy object, and specifically delegate + their calls like this: + + class Foo(Proxy): + __str__ = Delegate('__str__') + """ + + def __init__(self, subject): + """Wrap an object as a Proxy object""" + self._subject = subject + + def __getattr__(self, name): + """Retrieve an attribute from the wrapped object. If the named + attribute doesn't exist, AttributeError is raised""" + return getattr(self._subject, name) + + def get(self): + """Retrieve the entire wrapped object""" + return self._subject + + def __eq__(self, other): + if issubclass(other.__class__, self._subject.__class__): + return self._subject == other + return self.__dict__ == other.__dict__ + +class Delegate(object): + """A Python Descriptor class that delegates attribute fetches + to an underlying wrapped subject of a Proxy. Typical use: + + class Foo(Proxy): + __str__ = Delegate('__str__') + """ + def __init__(self, attribute): + self.attribute = attribute + def __get__(self, obj, cls): + if isinstance(obj, cls): + return getattr(obj._subject, self.attribute) + else: + return self + +# attempt to load the windows registry module: +can_read_reg = 0 +try: + import winreg + + can_read_reg = 1 + hkey_mod = winreg + + RegOpenKeyEx = winreg.OpenKeyEx + RegEnumKey = winreg.EnumKey + RegEnumValue = winreg.EnumValue + RegQueryValueEx = winreg.QueryValueEx + RegError = winreg.error + +except ImportError: + try: + import win32api + import win32con + can_read_reg = 1 + hkey_mod = win32con + + RegOpenKeyEx = win32api.RegOpenKeyEx + RegEnumKey = win32api.RegEnumKey + RegEnumValue = win32api.RegEnumValue + RegQueryValueEx = win32api.RegQueryValueEx + RegError = win32api.error + + except ImportError: + class _NoError(Exception): + pass + RegError = _NoError + +WinError = None +# Make sure we have a definition of WindowsError so we can +# run platform-independent tests of Windows functionality on +# platforms other than Windows. (WindowsError is, in fact, an +# OSError subclass on Windows.) +class PlainWindowsError(OSError): + pass +try: + WinError = WindowsError +except NameError: + WinError = PlainWindowsError + + +if can_read_reg: + HKEY_CLASSES_ROOT = hkey_mod.HKEY_CLASSES_ROOT + HKEY_LOCAL_MACHINE = hkey_mod.HKEY_LOCAL_MACHINE + HKEY_CURRENT_USER = hkey_mod.HKEY_CURRENT_USER + HKEY_USERS = hkey_mod.HKEY_USERS + + def RegGetValue(root, key): + """This utility function returns a value in the registry + without having to open the key first. Only available on + Windows platforms with a version of Python that can read the + registry. Returns the same thing as + SCons.Util.RegQueryValueEx, except you just specify the entire + path to the value, and don't have to bother opening the key + first. So: + + Instead of: + k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, + r'SOFTWARE\Microsoft\Windows\CurrentVersion') + out = SCons.Util.RegQueryValueEx(k, + 'ProgramFilesDir') + + You can write: + out = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE, + r'SOFTWARE\Microsoft\Windows\CurrentVersion\ProgramFilesDir') + """ + # I would use os.path.split here, but it's not a filesystem + # path... + p = key.rfind('\\') + 1 + keyp = key[:p-1] # -1 to omit trailing slash + val = key[p:] + k = RegOpenKeyEx(root, keyp) + return RegQueryValueEx(k,val) +else: + HKEY_CLASSES_ROOT = None + HKEY_LOCAL_MACHINE = None + HKEY_CURRENT_USER = None + HKEY_USERS = None + + def RegGetValue(root, key): + raise WinError + + def RegOpenKeyEx(root, key): + raise WinError + +if sys.platform == 'win32': + + def WhereIs(file, path=None, pathext=None, reject=[]): + if path is None: + try: + path = os.environ['PATH'] + except KeyError: + return None + if is_String(path): + path = path.split(os.pathsep) + if pathext is None: + try: + pathext = os.environ['PATHEXT'] + except KeyError: + pathext = '.COM;.EXE;.BAT;.CMD' + if is_String(pathext): + pathext = pathext.split(os.pathsep) + for ext in pathext: + if ext.lower() == file[-len(ext):].lower(): + pathext = [''] + break + if not is_List(reject) and not is_Tuple(reject): + reject = [reject] + for dir in path: + f = os.path.join(dir, file) + for ext in pathext: + fext = f + ext + if os.path.isfile(fext): + try: + reject.index(fext) + except ValueError: + return os.path.normpath(fext) + continue + return None + +elif os.name == 'os2': + + def WhereIs(file, path=None, pathext=None, reject=[]): + if path is None: + try: + path = os.environ['PATH'] + except KeyError: + return None + if is_String(path): + path = path.split(os.pathsep) + if pathext is None: + pathext = ['.exe', '.cmd'] + for ext in pathext: + if ext.lower() == file[-len(ext):].lower(): + pathext = [''] + break + if not is_List(reject) and not is_Tuple(reject): + reject = [reject] + for dir in path: + f = os.path.join(dir, file) + for ext in pathext: + fext = f + ext + if os.path.isfile(fext): + try: + reject.index(fext) + except ValueError: + return os.path.normpath(fext) + continue + return None + +else: + + def WhereIs(file, path=None, pathext=None, reject=[]): + import stat + if path is None: + try: + path = os.environ['PATH'] + except KeyError: + return None + if is_String(path): + path = path.split(os.pathsep) + if not is_List(reject) and not is_Tuple(reject): + reject = [reject] + for d in path: + f = os.path.join(d, file) + if os.path.isfile(f): + try: + st = os.stat(f) + except OSError: + # os.stat() raises OSError, not IOError if the file + # doesn't exist, so in this case we let IOError get + # raised so as to not mask possibly serious disk or + # network issues. + continue + if stat.S_IMODE(st[stat.ST_MODE]) & 0o111: + try: + reject.index(f) + except ValueError: + return os.path.normpath(f) + continue + return None + +def PrependPath(oldpath, newpath, sep = os.pathsep, + delete_existing=1, canonicalize=None): + """This prepends newpath elements to the given oldpath. Will only + add any particular path once (leaving the first one it encounters + and ignoring the rest, to preserve path order), and will + os.path.normpath and os.path.normcase all paths to help assure + this. This can also handle the case where the given old path + variable is a list instead of a string, in which case a list will + be returned instead of a string. + + Example: + Old Path: "/foo/bar:/foo" + New Path: "/biz/boom:/foo" + Result: "/biz/boom:/foo:/foo/bar" + + If delete_existing is 0, then adding a path that exists will + not move it to the beginning; it will stay where it is in the + list. + + If canonicalize is not None, it is applied to each element of + newpath before use. + """ + + orig = oldpath + is_list = 1 + paths = orig + if not is_List(orig) and not is_Tuple(orig): + paths = paths.split(sep) + is_list = 0 + + if is_String(newpath): + newpaths = newpath.split(sep) + elif not is_List(newpath) and not is_Tuple(newpath): + newpaths = [ newpath ] # might be a Dir + else: + newpaths = newpath + + if canonicalize: + newpaths=list(map(canonicalize, newpaths)) + + if not delete_existing: + # First uniquify the old paths, making sure to + # preserve the first instance (in Unix/Linux, + # the first one wins), and remembering them in normpaths. + # Then insert the new paths at the head of the list + # if they're not already in the normpaths list. + result = [] + normpaths = [] + for path in paths: + if not path: + continue + normpath = os.path.normpath(os.path.normcase(path)) + if normpath not in normpaths: + result.append(path) + normpaths.append(normpath) + newpaths.reverse() # since we're inserting at the head + for path in newpaths: + if not path: + continue + normpath = os.path.normpath(os.path.normcase(path)) + if normpath not in normpaths: + result.insert(0, path) + normpaths.append(normpath) + paths = result + + else: + newpaths = newpaths + paths # prepend new paths + + normpaths = [] + paths = [] + # now we add them only if they are unique + for path in newpaths: + normpath = os.path.normpath(os.path.normcase(path)) + if path and not normpath in normpaths: + paths.append(path) + normpaths.append(normpath) + + if is_list: + return paths + else: + return sep.join(paths) + +def AppendPath(oldpath, newpath, sep = os.pathsep, + delete_existing=1, canonicalize=None): + """This appends new path elements to the given old path. Will + only add any particular path once (leaving the last one it + encounters and ignoring the rest, to preserve path order), and + will os.path.normpath and os.path.normcase all paths to help + assure this. This can also handle the case where the given old + path variable is a list instead of a string, in which case a list + will be returned instead of a string. + + Example: + Old Path: "/foo/bar:/foo" + New Path: "/biz/boom:/foo" + Result: "/foo/bar:/biz/boom:/foo" + + If delete_existing is 0, then adding a path that exists + will not move it to the end; it will stay where it is in the list. + + If canonicalize is not None, it is applied to each element of + newpath before use. + """ + + orig = oldpath + is_list = 1 + paths = orig + if not is_List(orig) and not is_Tuple(orig): + paths = paths.split(sep) + is_list = 0 + + if is_String(newpath): + newpaths = newpath.split(sep) + elif not is_List(newpath) and not is_Tuple(newpath): + newpaths = [ newpath ] # might be a Dir + else: + newpaths = newpath + + if canonicalize: + newpaths=list(map(canonicalize, newpaths)) + + if not delete_existing: + # add old paths to result, then + # add new paths if not already present + # (I thought about using a dict for normpaths for speed, + # but it's not clear hashing the strings would be faster + # than linear searching these typically short lists.) + result = [] + normpaths = [] + for path in paths: + if not path: + continue + result.append(path) + normpaths.append(os.path.normpath(os.path.normcase(path))) + for path in newpaths: + if not path: + continue + normpath = os.path.normpath(os.path.normcase(path)) + if normpath not in normpaths: + result.append(path) + normpaths.append(normpath) + paths = result + else: + # start w/ new paths, add old ones if not present, + # then reverse. + newpaths = paths + newpaths # append new paths + newpaths.reverse() + + normpaths = [] + paths = [] + # now we add them only if they are unique + for path in newpaths: + normpath = os.path.normpath(os.path.normcase(path)) + if path and not normpath in normpaths: + paths.append(path) + normpaths.append(normpath) + paths.reverse() + + if is_list: + return paths + else: + return sep.join(paths) + +def AddPathIfNotExists(env_dict, key, path, sep=os.pathsep): + """This function will take 'key' out of the dictionary + 'env_dict', then add the path 'path' to that key if it is not + already there. This treats the value of env_dict[key] as if it + has a similar format to the PATH variable...a list of paths + separated by tokens. The 'path' will get added to the list if it + is not already there.""" + try: + is_list = 1 + paths = env_dict[key] + if not is_List(env_dict[key]): + paths = paths.split(sep) + is_list = 0 + if os.path.normcase(path) not in list(map(os.path.normcase, paths)): + paths = [ path ] + paths + if is_list: + env_dict[key] = paths + else: + env_dict[key] = sep.join(paths) + except KeyError: + env_dict[key] = path + +if sys.platform == 'cygwin': + def get_native_path(path): + """Transforms an absolute path into a native path for the system. In + Cygwin, this converts from a Cygwin path to a Windows one.""" + return os.popen('cygpath -w ' + path).read().replace('\n', '') +else: + def get_native_path(path): + """Transforms an absolute path into a native path for the system. + Non-Cygwin version, just leave the path alone.""" + return path + +display = DisplayEngine() + +def Split(arg): + if is_List(arg) or is_Tuple(arg): + return arg + elif is_String(arg): + return arg.split() + else: + return [arg] + +class CLVar(UserList): + """A class for command-line construction variables. + + This is a list that uses Split() to split an initial string along + white-space arguments, and similarly to split any strings that get + added. This allows us to Do the Right Thing with Append() and + Prepend() (as well as straight Python foo = env['VAR'] + 'arg1 + arg2') regardless of whether a user adds a list or a string to a + command-line construction variable. + """ + def __init__(self, seq = []): + UserList.__init__(self, Split(seq)) + def __add__(self, other): + return UserList.__add__(self, CLVar(other)) + def __radd__(self, other): + return UserList.__radd__(self, CLVar(other)) + def __str__(self): + return ' '.join(self.data) + + +class Selector(OrderedDict): + """A callable ordered dictionary that maps file suffixes to + dictionary values. We preserve the order in which items are added + so that get_suffix() calls always return the first suffix added.""" + def __call__(self, env, source, ext=None): + if ext is None: + try: + ext = source[0].get_suffix() + except IndexError: + ext = "" + try: + return self[ext] + except KeyError: + # Try to perform Environment substitution on the keys of + # the dictionary before giving up. + s_dict = {} + for (k,v) in self.items(): + if k is not None: + s_k = env.subst(k) + if s_k in s_dict: + # We only raise an error when variables point + # to the same suffix. If one suffix is literal + # and a variable suffix contains this literal, + # the literal wins and we don't raise an error. + raise KeyError(s_dict[s_k][0], k, s_k) + s_dict[s_k] = (k,v) + try: + return s_dict[ext][1] + except KeyError: + try: + return self[None] + except KeyError: + return None + + +if sys.platform == 'cygwin': + # On Cygwin, os.path.normcase() lies, so just report back the + # fact that the underlying Windows OS is case-insensitive. + def case_sensitive_suffixes(s1, s2): + return 0 +else: + def case_sensitive_suffixes(s1, s2): + return (os.path.normcase(s1) != os.path.normcase(s2)) + +def adjustixes(fname, pre, suf, ensure_suffix=False): + if pre: + path, fn = os.path.split(os.path.normpath(fname)) + if fn[:len(pre)] != pre: + fname = os.path.join(path, pre + fn) + # Only append a suffix if the suffix we're going to add isn't already + # there, and if either we've been asked to ensure the specific suffix + # is present or there's no suffix on it at all. + if suf and fname[-len(suf):] != suf and \ + (ensure_suffix or not splitext(fname)[1]): + fname = fname + suf + return fname + + + +# From Tim Peters, +# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560 +# ASPN: Python Cookbook: Remove duplicates from a sequence +# (Also in the printed Python Cookbook.) + +def unique(s): + """Return a list of the elements in s, but without duplicates. + + For example, unique([1,2,3,1,2,3]) is some permutation of [1,2,3], + unique("abcabc") some permutation of ["a", "b", "c"], and + unique(([1, 2], [2, 3], [1, 2])) some permutation of + [[2, 3], [1, 2]]. + + For best speed, all sequence elements should be hashable. Then + unique() will usually work in linear time. + + If not possible, the sequence elements should enjoy a total + ordering, and if list(s).sort() doesn't raise TypeError it's + assumed that they do enjoy a total ordering. Then unique() will + usually work in O(N*log2(N)) time. + + If that's not possible either, the sequence elements must support + equality-testing. Then unique() will usually work in quadratic + time. + """ + + n = len(s) + if n == 0: + return [] + + # Try using a dict first, as that's the fastest and will usually + # work. If it doesn't work, it will usually fail quickly, so it + # usually doesn't cost much to *try* it. It requires that all the + # sequence elements be hashable, and support equality comparison. + u = {} + try: + for x in s: + u[x] = 1 + except TypeError: + pass # move on to the next method + else: + return list(u.keys()) + del u + + # We can't hash all the elements. Second fastest is to sort, + # which brings the equal elements together; then duplicates are + # easy to weed out in a single pass. + # NOTE: Python's list.sort() was designed to be efficient in the + # presence of many duplicate elements. This isn't true of all + # sort functions in all languages or libraries, so this approach + # is more effective in Python than it may be elsewhere. + try: + t = sorted(s) + except TypeError: + pass # move on to the next method + else: + assert n > 0 + last = t[0] + lasti = i = 1 + while i < n: + if t[i] != last: + t[lasti] = last = t[i] + lasti = lasti + 1 + i = i + 1 + return t[:lasti] + del t + + # Brute force is all that's left. + u = [] + for x in s: + if x not in u: + u.append(x) + return u + + + +# From Alex Martelli, +# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560 +# ASPN: Python Cookbook: Remove duplicates from a sequence +# First comment, dated 2001/10/13. +# (Also in the printed Python Cookbook.) + +def uniquer(seq, idfun=None): + if idfun is None: + def idfun(x): return x + seen = {} + result = [] + for item in seq: + marker = idfun(item) + # in old Python versions: + # if seen.has_key(marker) + # but in new ones: + if marker in seen: continue + seen[marker] = 1 + result.append(item) + return result + +# A more efficient implementation of Alex's uniquer(), this avoids the +# idfun() argument and function-call overhead by assuming that all +# items in the sequence are hashable. + +def uniquer_hashables(seq): + seen = {} + result = [] + for item in seq: + #if not item in seen: + if item not in seen: + seen[item] = 1 + result.append(item) + return result + + +# Recipe 19.11 "Reading Lines with Continuation Characters", +# by Alex Martelli, straight from the Python CookBook (2nd edition). +def logical_lines(physical_lines, joiner=''.join): + logical_line = [] + for line in physical_lines: + stripped = line.rstrip() + if stripped.endswith('\\'): + # a line which continues w/the next physical line + logical_line.append(stripped[:-1]) + else: + # a line which does not continue, end of logical line + logical_line.append(line) + yield joiner(logical_line) + logical_line = [] + if logical_line: + # end of sequence implies end of last logical line + yield joiner(logical_line) + + +class LogicalLines(object): + """ Wrapper class for the logical_lines method. + + Allows us to read all "logical" lines at once from a + given file object. + """ + + def __init__(self, fileobj): + self.fileobj = fileobj + + def readlines(self): + result = [l for l in logical_lines(self.fileobj)] + return result + + +class UniqueList(UserList): + def __init__(self, seq = []): + UserList.__init__(self, seq) + self.unique = True + def __make_unique(self): + if not self.unique: + self.data = uniquer_hashables(self.data) + self.unique = True + def __lt__(self, other): + self.__make_unique() + return UserList.__lt__(self, other) + def __le__(self, other): + self.__make_unique() + return UserList.__le__(self, other) + def __eq__(self, other): + self.__make_unique() + return UserList.__eq__(self, other) + def __ne__(self, other): + self.__make_unique() + return UserList.__ne__(self, other) + def __gt__(self, other): + self.__make_unique() + return UserList.__gt__(self, other) + def __ge__(self, other): + self.__make_unique() + return UserList.__ge__(self, other) + def __cmp__(self, other): + self.__make_unique() + return UserList.__cmp__(self, other) + def __len__(self): + self.__make_unique() + return UserList.__len__(self) + def __getitem__(self, i): + self.__make_unique() + return UserList.__getitem__(self, i) + def __setitem__(self, i, item): + UserList.__setitem__(self, i, item) + self.unique = False + def __getslice__(self, i, j): + self.__make_unique() + return UserList.__getslice__(self, i, j) + def __setslice__(self, i, j, other): + UserList.__setslice__(self, i, j, other) + self.unique = False + def __add__(self, other): + result = UserList.__add__(self, other) + result.unique = False + return result + def __radd__(self, other): + result = UserList.__radd__(self, other) + result.unique = False + return result + def __iadd__(self, other): + result = UserList.__iadd__(self, other) + result.unique = False + return result + def __mul__(self, other): + result = UserList.__mul__(self, other) + result.unique = False + return result + def __rmul__(self, other): + result = UserList.__rmul__(self, other) + result.unique = False + return result + def __imul__(self, other): + result = UserList.__imul__(self, other) + result.unique = False + return result + def append(self, item): + UserList.append(self, item) + self.unique = False + def insert(self, i): + UserList.insert(self, i) + self.unique = False + def count(self, item): + self.__make_unique() + return UserList.count(self, item) + def index(self, item): + self.__make_unique() + return UserList.index(self, item) + def reverse(self): + self.__make_unique() + UserList.reverse(self) + def sort(self, *args, **kwds): + self.__make_unique() + return UserList.sort(self, *args, **kwds) + def extend(self, other): + UserList.extend(self, other) + self.unique = False + + +class Unbuffered(object): + """ + A proxy class that wraps a file object, flushing after every write, + and delegating everything else to the wrapped object. + """ + def __init__(self, file): + self.file = file + self.softspace = 0 ## backward compatibility; not supported in Py3k + def write(self, arg): + try: + self.file.write(arg) + self.file.flush() + except IOError: + # Stdout might be connected to a pipe that has been closed + # by now. The most likely reason for the pipe being closed + # is that the user has press ctrl-c. It this is the case, + # then SCons is currently shutdown. We therefore ignore + # IOError's here so that SCons can continue and shutdown + # properly so that the .sconsign is correctly written + # before SCons exits. + pass + def __getattr__(self, attr): + return getattr(self.file, attr) + +def make_path_relative(path): + """ makes an absolute path name to a relative pathname. + """ + if os.path.isabs(path): + drive_s,path = os.path.splitdrive(path) + + import re + if not drive_s: + path=re.compile("/*(.*)").findall(path)[0] + else: + path=path[1:] + + assert( not os.path.isabs( path ) ), path + return path + + + +# The original idea for AddMethod() and RenameFunction() come from the +# following post to the ActiveState Python Cookbook: +# +# ASPN: Python Cookbook : Install bound methods in an instance +# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/223613 +# +# That code was a little fragile, though, so the following changes +# have been wrung on it: +# +# * Switched the installmethod() "object" and "function" arguments, +# so the order reflects that the left-hand side is the thing being +# "assigned to" and the right-hand side is the value being assigned. +# +# * Changed explicit type-checking to the "try: klass = object.__class__" +# block in installmethod() below so that it still works with the +# old-style classes that SCons uses. +# +# * Replaced the by-hand creation of methods and functions with use of +# the "new" module, as alluded to in Alex Martelli's response to the +# following Cookbook post: +# +# ASPN: Python Cookbook : Dynamically added methods to a class +# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81732 + +def AddMethod(obj, function, name=None): + """ + Adds either a bound method to an instance or the function itself (or an unbound method in Python 2) to a class. + If name is ommited the name of the specified function + is used by default. + + Example:: + + a = A() + def f(self, x, y): + self.z = x + y + AddMethod(f, A, "add") + a.add(2, 4) + print(a.z) + AddMethod(lambda self, i: self.l[i], a, "listIndex") + print(a.listIndex(5)) + """ + if name is None: + name = function.__name__ + else: + function = RenameFunction(function, name) + + # Note the Python version checks - WLB + # Python 3.3 dropped the 3rd parameter from types.MethodType + if hasattr(obj, '__class__') and obj.__class__ is not type: + # "obj" is an instance, so it gets a bound method. + if sys.version_info[:2] > (3, 2): + method = MethodType(function, obj) + else: + method = MethodType(function, obj, obj.__class__) + else: + # Handle classes + method = function + + setattr(obj, name, method) + +def RenameFunction(function, name): + """ + Returns a function identical to the specified function, but with + the specified name. + """ + return FunctionType(function.__code__, + function.__globals__, + name, + function.__defaults__) + + +md5 = False + + +def MD5signature(s): + return str(s) + + +def MD5filesignature(fname, chunksize=65536): + with open(fname, "rb") as f: + result = f.read() + return result + +try: + import hashlib +except ImportError: + pass +else: + if hasattr(hashlib, 'md5'): + md5 = True + + def MD5signature(s): + """ + Generate a String of Hex digits representing the md5 signature of the string + :param s: either string or bytes. Normally should be bytes + :return: String of hex digits + """ + m = hashlib.md5() + + try: + m.update(to_bytes(s)) + except TypeError as e: + m.update(to_bytes(str(s))) + + return m.hexdigest() + + def MD5filesignature(fname, chunksize=65536): + """ + :param fname: + :param chunksize: + :return: String of Hex digits + """ + m = hashlib.md5() + f = open(fname, "rb") + while True: + blck = f.read(chunksize) + if not blck: + break + m.update(to_bytes(blck)) + f.close() + return m.hexdigest() + + +def MD5collect(signatures): + """ + Collects a list of signatures into an aggregate signature. + + signatures - a list of signatures + returns - the aggregate signature + """ + if len(signatures) == 1: + return signatures[0] + else: + return MD5signature(', '.join(signatures)) + + + +def silent_intern(x): + """ + Perform sys.intern() on the passed argument and return the result. + If the input is ineligible (e.g. a unicode string) the original argument is + returned and no exception is thrown. + """ + try: + return sys.intern(x) + except TypeError: + return x + + + +# From Dinu C. Gherman, +# Python Cookbook, second edition, recipe 6.17, p. 277. +# Also: +# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/68205 +# ASPN: Python Cookbook: Null Object Design Pattern + +#TODO??? class Null(object): +class Null(object): + """ Null objects always and reliably "do nothing." """ + def __new__(cls, *args, **kwargs): + if not '_instance' in vars(cls): + cls._instance = super(Null, cls).__new__(cls, *args, **kwargs) + return cls._instance + def __init__(self, *args, **kwargs): + pass + def __call__(self, *args, **kwargs): + return self + def __repr__(self): + return "Null(0x%08X)" % id(self) + def __nonzero__(self): + return False + def __bool__(self): + return False + def __getattr__(self, name): + return self + def __setattr__(self, name, value): + return self + def __delattr__(self, name): + return self + +class NullSeq(Null): + def __len__(self): + return 0 + def __iter__(self): + return iter(()) + def __getitem__(self, i): + return self + def __delitem__(self, i): + return self + def __setitem__(self, i, v): + return self + + +del __revision__ + + +def to_bytes(s): + if s is None: + return b'None' + if not PY3 and isinstance(s, UnicodeType): + # PY2, must encode unicode + return bytearray(s, 'utf-8') + if isinstance (s, (bytes, bytearray)) or bytes is str: + # Above case not covered here as py2 bytes and strings are the same + return s + return bytes(s, 'utf-8') + + +def to_str(s): + if s is None: + return 'None' + if bytes is str or is_String(s): + return s + return str (s, 'utf-8') + + +def cmp(a, b): + """ + Define cmp because it's no longer available in python3 + Works under python 2 as well + """ + return (a > b) - (a < b) + + +def get_env_bool(env, name, default=False): + """Get a value of env[name] converted to boolean. The value of env[name] is + interpreted as follows: 'true', 'yes', 'y', 'on' (case insensitive) and + anything convertible to int that yields non-zero integer are True values; + '0', 'false', 'no', 'n' and 'off' (case insensitive) are False values. For + all other cases, default value is returned. + + :Parameters: + - `env` - dict or dict-like object, a convainer with variables + - `name` - name of the variable in env to be returned + - `default` - returned when env[name] does not exist or can't be converted to bool + """ + try: + var = env[name] + except KeyError: + return default + try: + return bool(int(var)) + except ValueError: + if str(var).lower() in ('true', 'yes', 'y', 'on'): + return True + elif str(var).lower() in ('false', 'no', 'n', 'off'): + return False + else: + return default + + +def get_os_env_bool(name, default=False): + """Same as get_env_bool(os.environ, name, default).""" + return get_env_bool(os.environ, name, default) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Variables/BoolVariable.py b/tools/scons/scons-local-3.0.5/SCons/Variables/BoolVariable.py new file mode 100755 index 0000000000..71b554ad18 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Variables/BoolVariable.py @@ -0,0 +1,89 @@ +"""engine.SCons.Variables.BoolVariable + +This file defines the option type for SCons implementing true/false values. + +Usage example:: + + opts = Variables() + opts.Add(BoolVariable('embedded', 'build for an embedded system', 0)) + ... + if env['embedded'] == 1: + ... +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Variables/BoolVariable.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +__all__ = ['BoolVariable',] + +import SCons.Errors + +__true_strings = ('y', 'yes', 'true', 't', '1', 'on' , 'all' ) +__false_strings = ('n', 'no', 'false', 'f', '0', 'off', 'none') + + +def _text2bool(val): + """ + Converts strings to True/False depending on the 'truth' expressed by + the string. If the string can't be converted, the original value + will be returned. + + See '__true_strings' and '__false_strings' for values considered + 'true' or 'false respectively. + + This is usable as 'converter' for SCons' Variables. + """ + lval = val.lower() + if lval in __true_strings: return True + if lval in __false_strings: return False + raise ValueError("Invalid value for boolean option: %s" % val) + + +def _validator(key, val, env): + """ + Validates the given value to be either '0' or '1'. + + This is usable as 'validator' for SCons' Variables. + """ + if not env[key] in (True, False): + raise SCons.Errors.UserError( + 'Invalid value for boolean option %s: %s' % (key, env[key])) + + +def BoolVariable(key, help, default): + """ + The input parameters describe a boolean option, thus they are + returned with the correct converter and validator appended. The + 'help' text will by appended by '(yes|no) to show the valid + valued. The result is usable for input to opts.Add(). + """ + return (key, '%s (yes|no)' % help, default, + _validator, _text2bool) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Variables/EnumVariable.py b/tools/scons/scons-local-3.0.5/SCons/Variables/EnumVariable.py new file mode 100755 index 0000000000..4995bb13bd --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Variables/EnumVariable.py @@ -0,0 +1,101 @@ +"""engine.SCons.Variables.EnumVariable + +This file defines the option type for SCons allowing only specified +input-values. + +Usage example:: + + opts = Variables() + opts.Add(EnumVariable('debug', 'debug output and symbols', 'no', + allowed_values=('yes', 'no', 'full'), + map={}, ignorecase=2)) + ... + if env['debug'] == 'full': + ... +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Variables/EnumVariable.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +__all__ = ['EnumVariable',] + + +import SCons.Errors + +def _validator(key, val, env, vals): + if not val in vals: + raise SCons.Errors.UserError( + 'Invalid value for option %s: %s. Valid values are: %s' % (key, val, vals)) + + +def EnumVariable(key, help, default, allowed_values, map={}, ignorecase=0): + """ + The input parameters describe an option with only certain values + allowed. They are returned with an appropriate converter and + validator appended. The result is usable for input to + Variables.Add(). + + 'key' and 'default' are the values to be passed on to Variables.Add(). + + 'help' will be appended by the allowed values automatically + + 'allowed_values' is a list of strings, which are allowed as values + for this option. + + The 'map'-dictionary may be used for converting the input value + into canonical values (e.g. for aliases). + + 'ignorecase' defines the behaviour of the validator: + + If ignorecase == 0, the validator/converter are case-sensitive. + If ignorecase == 1, the validator/converter are case-insensitive. + If ignorecase == 2, the validator/converter is case-insensitive and the converted value will always be lower-case. + + The 'validator' tests whether the value is in the list of allowed values. The 'converter' converts input values + according to the given 'map'-dictionary (unmapped input values are returned unchanged). + """ + + help = '%s (%s)' % (help, '|'.join(allowed_values)) + # define validator + if ignorecase >= 1: + validator = lambda key, val, env: \ + _validator(key, val.lower(), env, allowed_values) + else: + validator = lambda key, val, env: \ + _validator(key, val, env, allowed_values) + # define converter + if ignorecase == 2: + converter = lambda val: map.get(val.lower(), val).lower() + elif ignorecase == 1: + converter = lambda val: map.get(val.lower(), val) + else: + converter = lambda val: map.get(val, val) + return (key, help, default, validator, converter) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Variables/ListVariable.py b/tools/scons/scons-local-3.0.5/SCons/Variables/ListVariable.py new file mode 100755 index 0000000000..499538234e --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Variables/ListVariable.py @@ -0,0 +1,135 @@ +"""engine.SCons.Variables.ListVariable + +This file defines the option type for SCons implementing 'lists'. + +A 'list' option may either be 'all', 'none' or a list of names +separated by comma. After the option has been processed, the option +value holds either the named list elements, all list elements or no +list elements at all. + +Usage example:: + + list_of_libs = Split('x11 gl qt ical') + + opts = Variables() + opts.Add(ListVariable('shared', + 'libraries to build as shared libraries', + 'all', + elems = list_of_libs)) + ... + for lib in list_of_libs: + if lib in env['shared']: + env.SharedObject(...) + else: + env.Object(...) +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +__revision__ = "src/engine/SCons/Variables/ListVariable.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +# Known Bug: This should behave like a Set-Type, but does not really, +# since elements can occur twice. + +__all__ = ['ListVariable',] + +import collections + +import SCons.Util + + +class _ListVariable(collections.UserList): + def __init__(self, initlist=[], allowedElems=[]): + collections.UserList.__init__(self, [_f for _f in initlist if _f]) + self.allowedElems = sorted(allowedElems) + + def __cmp__(self, other): + raise NotImplementedError + def __eq__(self, other): + raise NotImplementedError + def __ge__(self, other): + raise NotImplementedError + def __gt__(self, other): + raise NotImplementedError + def __le__(self, other): + raise NotImplementedError + def __lt__(self, other): + raise NotImplementedError + def __str__(self): + if len(self) == 0: + return 'none' + self.data.sort() + if self.data == self.allowedElems: + return 'all' + else: + return ','.join(self) + def prepare_to_store(self): + return self.__str__() + +def _converter(val, allowedElems, mapdict): + """ + """ + if val == 'none': + val = [] + elif val == 'all': + val = allowedElems + else: + val = [_f for _f in val.split(',') if _f] + val = [mapdict.get(v, v) for v in val] + notAllowed = [v for v in val if not v in allowedElems] + if notAllowed: + raise ValueError("Invalid value(s) for option: %s" % + ','.join(notAllowed)) + return _ListVariable(val, allowedElems) + + +## def _validator(key, val, env): +## """ +## """ +## # todo: write validator for pgk list +## return 1 + + +def ListVariable(key, help, default, names, map={}): + """ + The input parameters describe a 'package list' option, thus they + are returned with the correct converter and validator appended. The + result is usable for input to opts.Add() . + + A 'package list' option may either be 'all', 'none' or a list of + package names (separated by space). + """ + names_str = 'allowed names: %s' % ' '.join(names) + if SCons.Util.is_List(default): + default = ','.join(default) + help = '\n '.join( + (help, '(all|none|comma-separated list of names)', names_str)) + return (key, help, default, + None, #_validator, + lambda val: _converter(val, names, map)) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Variables/PackageVariable.py b/tools/scons/scons-local-3.0.5/SCons/Variables/PackageVariable.py new file mode 100755 index 0000000000..e1d2e3da5e --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Variables/PackageVariable.py @@ -0,0 +1,106 @@ +"""engine.SCons.Variables.PackageVariable + +This file defines the option type for SCons implementing 'package +activation'. + +To be used whenever a 'package' may be enabled/disabled and the +package path may be specified. + +Usage example: + + Examples: + x11=no (disables X11 support) + x11=yes (will search for the package installation dir) + x11=/usr/local/X11 (will check this path for existence) + + To replace autoconf's --with-xxx=yyy :: + + opts = Variables() + opts.Add(PackageVariable('x11', + 'use X11 installed here (yes = search some places', + 'yes')) + ... + if env['x11'] == True: + dir = ... search X11 in some standard places ... + env['x11'] = dir + if env['x11']: + ... build with x11 ... +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Variables/PackageVariable.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +__all__ = ['PackageVariable',] + +import SCons.Errors + +__enable_strings = ('1', 'yes', 'true', 'on', 'enable', 'search') +__disable_strings = ('0', 'no', 'false', 'off', 'disable') + +def _converter(val): + """ + """ + lval = val.lower() + if lval in __enable_strings: return True + if lval in __disable_strings: return False + #raise ValueError("Invalid value for boolean option: %s" % val) + return val + + +def _validator(key, val, env, searchfunc): + # NB: searchfunc is currently undocumented and unsupported + """ + """ + # TODO write validator, check for path + import os + if env[key] is True: + if searchfunc: + env[key] = searchfunc(key, val) + elif env[key] and not os.path.exists(val): + raise SCons.Errors.UserError( + 'Path does not exist for option %s: %s' % (key, val)) + + +def PackageVariable(key, help, default, searchfunc=None): + # NB: searchfunc is currently undocumented and unsupported + """ + The input parameters describe a 'package list' option, thus they + are returned with the correct converter and validator appended. The + result is usable for input to opts.Add() . + + A 'package list' option may either be 'all', 'none' or a list of + package names (separated by space). + """ + help = '\n '.join( + (help, '( yes | no | /path/to/%s )' % key)) + return (key, help, default, + lambda k, v, e: _validator(k,v,e,searchfunc), + _converter) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Variables/PathVariable.py b/tools/scons/scons-local-3.0.5/SCons/Variables/PathVariable.py new file mode 100755 index 0000000000..8003ba672f --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Variables/PathVariable.py @@ -0,0 +1,145 @@ +"""SCons.Variables.PathVariable + +This file defines an option type for SCons implementing path settings. + +To be used whenever a user-specified path override should be allowed. + +Arguments to PathVariable are: + option-name = name of this option on the command line (e.g. "prefix") + option-help = help string for option + option-dflt = default value for this option + validator = [optional] validator for option value. Predefined validators are: + + PathAccept -- accepts any path setting; no validation + PathIsDir -- path must be an existing directory + PathIsDirCreate -- path must be a dir; will create + PathIsFile -- path must be a file + PathExists -- path must exist (any type) [default] + + The validator is a function that is called and which + should return True or False to indicate if the path + is valid. The arguments to the validator function + are: (key, val, env). The key is the name of the + option, the val is the path specified for the option, + and the env is the env to which the Options have been + added. + +Usage example:: + + Examples: + prefix=/usr/local + + opts = Variables() + + opts = Variables() + opts.Add(PathVariable('qtdir', + 'where the root of Qt is installed', + qtdir, PathIsDir)) + opts.Add(PathVariable('qt_includes', + 'where the Qt includes are installed', + '$qtdir/includes', PathIsDirCreate)) + opts.Add(PathVariable('qt_libraries', + 'where the Qt library is installed', + '$qtdir/lib')) + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Variables/PathVariable.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +__all__ = ['PathVariable',] + +import os +import os.path + +import SCons.Errors + +class _PathVariableClass(object): + + def PathAccept(self, key, val, env): + """Accepts any path, no checking done.""" + pass + + def PathIsDir(self, key, val, env): + """Validator to check if Path is a directory.""" + if not os.path.isdir(val): + if os.path.isfile(val): + m = 'Directory path for option %s is a file: %s' + else: + m = 'Directory path for option %s does not exist: %s' + raise SCons.Errors.UserError(m % (key, val)) + + def PathIsDirCreate(self, key, val, env): + """Validator to check if Path is a directory, + creating it if it does not exist.""" + if os.path.isfile(val): + m = 'Path for option %s is a file, not a directory: %s' + raise SCons.Errors.UserError(m % (key, val)) + if not os.path.isdir(val): + os.makedirs(val) + + def PathIsFile(self, key, val, env): + """Validator to check if Path is a file""" + if not os.path.isfile(val): + if os.path.isdir(val): + m = 'File path for option %s is a directory: %s' + else: + m = 'File path for option %s does not exist: %s' + raise SCons.Errors.UserError(m % (key, val)) + + def PathExists(self, key, val, env): + """Validator to check if Path exists""" + if not os.path.exists(val): + m = 'Path for option %s does not exist: %s' + raise SCons.Errors.UserError(m % (key, val)) + + def __call__(self, key, help, default, validator=None): + """ + The input parameters describe a 'path list' option, thus they + are returned with the correct converter and validator appended. The + result is usable for input to opts.Add() . + + The 'default' option specifies the default path to use if the + user does not specify an override with this option. + + validator is a validator, see this file for examples + """ + if validator is None: + validator = self.PathExists + + if SCons.Util.is_List(key) or SCons.Util.is_Tuple(key): + return (key, '%s ( /path/to/%s )' % (help, key[0]), default, + validator, None) + else: + return (key, '%s ( /path/to/%s )' % (help, key), default, + validator, None) + +PathVariable = _PathVariableClass() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Variables/__init__.py b/tools/scons/scons-local-3.0.5/SCons/Variables/__init__.py new file mode 100755 index 0000000000..c218e18702 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Variables/__init__.py @@ -0,0 +1,327 @@ +"""engine.SCons.Variables + +This file defines the Variables class that is used to add user-friendly +customizable variables to an SCons build. +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +__revision__ = "src/engine/SCons/Variables/__init__.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os.path +import sys +from functools import cmp_to_key + +import SCons.Environment +import SCons.Errors +import SCons.Util +import SCons.Warnings + +from .BoolVariable import BoolVariable # okay +from .EnumVariable import EnumVariable # okay +from .ListVariable import ListVariable # naja +from .PackageVariable import PackageVariable # naja +from .PathVariable import PathVariable # okay + + +class Variables(object): + instance=None + + """ + Holds all the options, updates the environment with the variables, + and renders the help text. + """ + def __init__(self, files=None, args=None, is_global=1): + """ + files - [optional] List of option configuration files to load + (backward compatibility) If a single string is passed it is + automatically placed in a file list + """ + # initialize arguments + if files is None: + files = [] + if args is None: + args = {} + self.options = [] + self.args = args + if not SCons.Util.is_List(files): + if files: + files = [ files ] + else: + files = [] + self.files = files + self.unknown = {} + + # create the singleton instance + if is_global: + self=Variables.instance + + if not Variables.instance: + Variables.instance=self + + def _do_add(self, key, help="", default=None, validator=None, converter=None): + class Variable(object): + pass + + option = Variable() + + # if we get a list or a tuple, we take the first element as the + # option key and store the remaining in aliases. + if SCons.Util.is_List(key) or SCons.Util.is_Tuple(key): + option.key = key[0] + option.aliases = key[1:] + else: + option.key = key + option.aliases = [ key ] + option.help = help + option.default = default + option.validator = validator + option.converter = converter + + self.options.append(option) + + # options might be added after the 'unknown' dict has been set up, + # so we remove the key and all its aliases from that dict + for alias in list(option.aliases) + [ option.key ]: + if alias in self.unknown: + del self.unknown[alias] + + def keys(self): + """ + Returns the keywords for the options + """ + return [o.key for o in self.options] + + def Add(self, key, help="", default=None, validator=None, converter=None, **kw): + """ + Add an option. + + + @param key: the name of the variable, or a list or tuple of arguments + @param help: optional help text for the options + @param default: optional default value + @param validator: optional function that is called to validate the option's value + @type validator: Called with (key, value, environment) + @param converter: optional function that is called to convert the option's value before putting it in the environment. + """ + + if SCons.Util.is_List(key) or isinstance(key, tuple): + self._do_add(*key) + return + + if not SCons.Util.is_String(key) or \ + not SCons.Environment.is_valid_construction_var(key): + raise SCons.Errors.UserError("Illegal Variables.Add() key `%s'" % str(key)) + + self._do_add(key, help, default, validator, converter) + + def AddVariables(self, *optlist): + """ + Add a list of options. + + Each list element is a tuple/list of arguments to be passed on + to the underlying method for adding options. + + Example:: + + opt.AddVariables( + ('debug', '', 0), + ('CC', 'The C compiler'), + ('VALIDATE', 'An option for testing validation', 'notset', + validator, None), + ) + + """ + + for o in optlist: + self._do_add(*o) + + + def Update(self, env, args=None): + """ + Update an environment with the option variables. + + env - the environment to update. + """ + + values = {} + + # first set the defaults: + for option in self.options: + if not option.default is None: + values[option.key] = option.default + + # next set the value specified in the options file + for filename in self.files: + if os.path.exists(filename): + dir = os.path.split(os.path.abspath(filename))[0] + if dir: + sys.path.insert(0, dir) + try: + values['__name__'] = filename + with open(filename, 'r') as f: + contents = f.read() + exec(contents, {}, values) + finally: + if dir: + del sys.path[0] + del values['__name__'] + + # set the values specified on the command line + if args is None: + args = self.args + + for arg, value in args.items(): + added = False + for option in self.options: + if arg in list(option.aliases) + [ option.key ]: + values[option.key] = value + added = True + if not added: + self.unknown[arg] = value + + # put the variables in the environment: + # (don't copy over variables that are not declared as options) + for option in self.options: + try: + env[option.key] = values[option.key] + except KeyError: + pass + + # Call the convert functions: + for option in self.options: + if option.converter and option.key in values: + value = env.subst('${%s}'%option.key) + try: + try: + env[option.key] = option.converter(value) + except TypeError: + env[option.key] = option.converter(value, env) + except ValueError as x: + raise SCons.Errors.UserError('Error converting option: %s\n%s'%(option.key, x)) + + + # Finally validate the values: + for option in self.options: + if option.validator and option.key in values: + option.validator(option.key, env.subst('${%s}'%option.key), env) + + def UnknownVariables(self): + """ + Returns any options in the specified arguments lists that + were not known, declared options in this object. + """ + return self.unknown + + def Save(self, filename, env): + """ + Saves all the options in the given file. This file can + then be used to load the options next run. This can be used + to create an option cache file. + + filename - Name of the file to save into + env - the environment get the option values from + """ + + # Create the file and write out the header + try: + fh = open(filename, 'w') + + try: + # Make an assignment in the file for each option + # within the environment that was assigned a value + # other than the default. + for option in self.options: + try: + value = env[option.key] + try: + prepare = value.prepare_to_store + except AttributeError: + try: + eval(repr(value)) + except KeyboardInterrupt: + raise + except: + # Convert stuff that has a repr() that + # cannot be evaluated into a string + value = SCons.Util.to_String(value) + else: + value = prepare() + + defaultVal = env.subst(SCons.Util.to_String(option.default)) + if option.converter: + defaultVal = option.converter(defaultVal) + + if str(env.subst('${%s}' % option.key)) != str(defaultVal): + fh.write('%s = %s\n' % (option.key, repr(value))) + except KeyError: + pass + finally: + fh.close() + + except IOError as x: + raise SCons.Errors.UserError('Error writing options to file: %s\n%s' % (filename, x)) + + def GenerateHelpText(self, env, sort=None): + """ + Generate the help text for the options. + + env - an environment that is used to get the current values + of the options. + cmp - Either a function as follows: The specific sort function should take two arguments and return -1, 0 or 1 + or a boolean to indicate if it should be sorted. + """ + + if callable(sort): + options = sorted(self.options, key=cmp_to_key(lambda x,y: sort(x.key,y.key))) + elif sort is True: + options = sorted(self.options, key=lambda x: x.key) + else: + options = self.options + + def format(opt, self=self, env=env): + if opt.key in env: + actual = env.subst('${%s}' % opt.key) + else: + actual = None + return self.FormatVariableHelpText(env, opt.key, opt.help, opt.default, actual, opt.aliases) + lines = [_f for _f in map(format, options) if _f] + + return ''.join(lines) + + format = '\n%s: %s\n default: %s\n actual: %s\n' + format_ = '\n%s: %s\n default: %s\n actual: %s\n aliases: %s\n' + + def FormatVariableHelpText(self, env, key, help, default, actual, aliases=[]): + # Don't display the key name itself as an alias. + aliases = [a for a in aliases if a != key] + if len(aliases)==0: + return self.format % (key, help, default, actual) + else: + return self.format_ % (key, help, default, actual, aliases) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/Warnings.py b/tools/scons/scons-local-3.0.5/SCons/Warnings.py new file mode 100755 index 0000000000..d3143fd0fb --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/Warnings.py @@ -0,0 +1,251 @@ +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +"""SCons.Warnings + +This file implements the warnings framework for SCons. + +""" + +__revision__ = "src/engine/SCons/Warnings.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import sys + +import SCons.Errors + +class Warning(SCons.Errors.UserError): + pass + +class WarningOnByDefault(Warning): + pass + + +# NOTE: If you add a new warning class, add it to the man page, too! +class TargetNotBuiltWarning(Warning): # Should go to OnByDefault + pass + +class CacheVersionWarning(WarningOnByDefault): + pass + +class CacheWriteErrorWarning(Warning): + pass + +class CorruptSConsignWarning(WarningOnByDefault): + pass + +class DependencyWarning(Warning): + pass + +class DevelopmentVersionWarning(WarningOnByDefault): + pass + +class DuplicateEnvironmentWarning(WarningOnByDefault): + pass + +class FutureReservedVariableWarning(WarningOnByDefault): + pass + +class LinkWarning(WarningOnByDefault): + pass + +class MisleadingKeywordsWarning(WarningOnByDefault): + pass + +class MissingSConscriptWarning(WarningOnByDefault): + pass + +class NoObjectCountWarning(WarningOnByDefault): + pass + +class NoParallelSupportWarning(WarningOnByDefault): + pass + +class ReservedVariableWarning(WarningOnByDefault): + pass + +class StackSizeWarning(WarningOnByDefault): + pass + +class VisualCMissingWarning(WarningOnByDefault): + pass + +# Used when MSVC_VERSION and MSVS_VERSION do not point to the +# same version (MSVS_VERSION is deprecated) +class VisualVersionMismatch(WarningOnByDefault): + pass + +class VisualStudioMissingWarning(Warning): + pass + +class FortranCxxMixWarning(LinkWarning): + pass + + +# Deprecation warnings + +class FutureDeprecatedWarning(Warning): + pass + +class DeprecatedWarning(Warning): + pass + +class MandatoryDeprecatedWarning(DeprecatedWarning): + pass + + +# Special case; base always stays DeprecatedWarning +class PythonVersionWarning(DeprecatedWarning): + pass + +class DeprecatedSourceCodeWarning(FutureDeprecatedWarning): + pass + +class DeprecatedBuildDirWarning(DeprecatedWarning): + pass + +class TaskmasterNeedsExecuteWarning(DeprecatedWarning): + pass + +class DeprecatedCopyWarning(MandatoryDeprecatedWarning): + pass + +class DeprecatedOptionsWarning(MandatoryDeprecatedWarning): + pass + +class DeprecatedSourceSignaturesWarning(MandatoryDeprecatedWarning): + pass + +class DeprecatedTargetSignaturesWarning(MandatoryDeprecatedWarning): + pass + +class DeprecatedDebugOptionsWarning(MandatoryDeprecatedWarning): + pass + +class DeprecatedSigModuleWarning(MandatoryDeprecatedWarning): + pass + +class DeprecatedBuilderKeywordsWarning(MandatoryDeprecatedWarning): + pass + +class DeprecatedMissingSConscriptWarning(DeprecatedWarning): + pass + + +# The below is a list of 2-tuples. The first element is a class object. +# The second element is true if that class is enabled, false if it is disabled. +_enabled = [] + +# If set, raise the warning as an exception +_warningAsException = 0 + +# If not None, a function to call with the warning +_warningOut = None + +def suppressWarningClass(clazz): + """Suppresses all warnings that are of type clazz or + derived from clazz.""" + _enabled.insert(0, (clazz, 0)) + +def enableWarningClass(clazz): + """Enables all warnings that are of type clazz or + derived from clazz.""" + _enabled.insert(0, (clazz, 1)) + +def warningAsException(flag=1): + """Turn warnings into exceptions. Returns the old value of the flag.""" + global _warningAsException + old = _warningAsException + _warningAsException = flag + return old + +def warn(clazz, *args): + global _enabled, _warningAsException, _warningOut + + warning = clazz(args) + for cls, flag in _enabled: + if isinstance(warning, cls): + if flag: + if _warningAsException: + raise warning + + if _warningOut: + _warningOut(warning) + break + +def process_warn_strings(arguments): + """Process string specifications of enabling/disabling warnings, + as passed to the --warn option or the SetOption('warn') function. + + + An argument to this option should be of the form + or no-. The warning class is munged in order + to get an actual class name from the classes above, which we + need to pass to the {enable,disable}WarningClass() functions. + The supplied is split on hyphens, each element + is capitalized, then smushed back together. Then the string + "Warning" is appended to get the class name. + + For example, 'deprecated' will enable the DeprecatedWarning + class. 'no-dependency' will disable the DependencyWarning class. + + As a special case, --warn=all and --warn=no-all will enable or + disable (respectively) the base Warning class of all warnings. + + """ + + def _capitalize(s): + if s[:5] == "scons": + return "SCons" + s[5:] + else: + return s.capitalize() + + for arg in arguments: + + elems = arg.lower().split('-') + enable = 1 + if elems[0] == 'no': + enable = 0 + del elems[0] + + if len(elems) == 1 and elems[0] == 'all': + class_name = "Warning" + else: + class_name = ''.join(map(_capitalize, elems)) + "Warning" + try: + clazz = globals()[class_name] + except KeyError: + sys.stderr.write("No warning type: '%s'\n" % arg) + else: + if enable: + enableWarningClass(clazz) + elif issubclass(clazz, MandatoryDeprecatedWarning): + fmt = "Can not disable mandataory warning: '%s'\n" + sys.stderr.write(fmt % arg) + else: + suppressWarningClass(clazz) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/__init__.py b/tools/scons/scons-local-3.0.5/SCons/__init__.py new file mode 100755 index 0000000000..27c37ebf2b --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/__init__.py @@ -0,0 +1,49 @@ +"""SCons + +The main package for the SCons software construction utility. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/__init__.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +__version__ = "3.0.5" + +__build__ = "a56bbd8c09fb219ab8a9673330ffcd55279219d0" + +__buildsys__ = "kufra" + +__date__ = "2019-03-26 23:16:31" + +__developer__ = "bdeegan" + +# make sure compatibility is always in place +import SCons.compat + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/compat/__init__.py b/tools/scons/scons-local-3.0.5/SCons/compat/__init__.py new file mode 100755 index 0000000000..784657753c --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/compat/__init__.py @@ -0,0 +1,212 @@ +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__doc__ = """ +SCons compatibility package for old Python versions + +This subpackage holds modules that provide backwards-compatible +implementations of various things that we'd like to use in SCons but which +only show up in later versions of Python than the early, old version(s) +we still support. + +Other code will not generally reference things in this package through +the SCons.compat namespace. The modules included here add things to +the builtins namespace or the global module list so that the rest +of our code can use the objects and names imported here regardless of +Python version. + +The rest of the things here will be in individual compatibility modules +that are either: 1) suitably modified copies of the future modules that +we want to use; or 2) backwards compatible re-implementations of the +specific portions of a future module's API that we want to use. + +GENERAL WARNINGS: Implementations of functions in the SCons.compat +modules are *NOT* guaranteed to be fully compliant with these functions in +later versions of Python. We are only concerned with adding functionality +that we actually use in SCons, so be wary if you lift this code for +other uses. (That said, making these more nearly the same as later, +official versions is still a desirable goal, we just don't need to be +obsessive about it.) + +We name the compatibility modules with an initial '_scons_' (for example, +_scons_subprocess.py is our compatibility module for subprocess) so +that we can still try to import the real module name and fall back to +our compatibility module if we get an ImportError. The import_as() +function defined below loads the module as the "real" name (without the +'_scons'), after which all of the "import {module}" statements in the +rest of our code will find our pre-loaded compatibility module. +""" + +__revision__ = "src/engine/SCons/compat/__init__.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import os +import sys +import imp # Use the "imp" module to protect imports from fixers. + +PYPY = hasattr(sys, 'pypy_translation_info') + + +def import_as(module, name): + """ + Imports the specified module (from our local directory) as the + specified name, returning the loaded module object. + """ + dir = os.path.split(__file__)[0] + return imp.load_module(name, *imp.find_module(module, [dir])) + + +def rename_module(new, old): + """ + Attempts to import the old module and load it under the new name. + Used for purely cosmetic name changes in Python 3.x. + """ + try: + sys.modules[new] = imp.load_module(old, *imp.find_module(old)) + return True + except ImportError: + return False + + +# TODO: FIXME +# In 3.x, 'pickle' automatically loads the fast version if available. +rename_module('pickle', 'cPickle') + +# Default pickle protocol. Higher protocols are more efficient/featureful +# but incompatible with older Python versions. On Python 2.7 this is 2. +# Negative numbers choose the highest available protocol. +import pickle + +# Was pickle.HIGHEST_PROTOCOL +# Changed to 2 so py3.5+'s pickle will be compatible with py2.7. +PICKLE_PROTOCOL = pickle.HIGHEST_PROTOCOL + +# TODO: FIXME +# In 3.x, 'profile' automatically loads the fast version if available. +rename_module('profile', 'cProfile') + +# TODO: FIXME +# Before Python 3.0, the 'queue' module was named 'Queue'. +rename_module('queue', 'Queue') + +# TODO: FIXME +# Before Python 3.0, the 'winreg' module was named '_winreg' +rename_module('winreg', '_winreg') + +# Python 3 moved builtin intern() to sys package +# To make porting easier, make intern always live +# in sys package (for python 2.7.x) +try: + sys.intern +except AttributeError: + # We must be using python 2.7.x so monkey patch + # intern into the sys package + sys.intern = intern + +# Preparing for 3.x. UserDict, UserList, UserString are in +# collections for 3.x, but standalone in 2.7.x +import collections + +try: + collections.UserDict +except AttributeError: + exec ('from UserDict import UserDict as _UserDict') + collections.UserDict = _UserDict + del _UserDict + +try: + collections.UserList +except AttributeError: + exec ('from UserList import UserList as _UserList') + collections.UserList = _UserList + del _UserList + +try: + collections.UserString +except AttributeError: + exec ('from UserString import UserString as _UserString') + collections.UserString = _UserString + del _UserString + + +import shutil +try: + shutil.SameFileError +except AttributeError: + class SameFileError(Exception): + pass + + shutil.SameFileError = SameFileError + +def with_metaclass(meta, *bases): + """ + Function from jinja2/_compat.py. License: BSD. + + Use it like this:: + + class BaseForm(object): + pass + + class FormType(type): + pass + + class Form(with_metaclass(FormType, BaseForm)): + pass + + This requires a bit of explanation: the basic idea is to make a + dummy metaclass for one level of class instantiation that replaces + itself with the actual metaclass. Because of internal type checks + we also need to make sure that we downgrade the custom metaclass + for one level to something closer to type (that's why __call__ and + __init__ comes back from type etc.). + + This has the advantage over six.with_metaclass of not introducing + dummy classes into the final MRO. + """ + + class metaclass(meta): + __call__ = type.__call__ + __init__ = type.__init__ + + def __new__(cls, name, this_bases, d): + if this_bases is None: + return type.__new__(cls, name, (), d) + return meta(name, bases, d) + + return metaclass('temporary_class', None, {}) + + +class NoSlotsPyPy(type): + """ + Workaround for PyPy not working well with __slots__ and __class__ assignment. + """ + + def __new__(meta, name, bases, dct): + if PYPY and '__slots__' in dct: + dct.pop('__slots__') + return super(NoSlotsPyPy, meta).__new__(meta, name, bases, dct) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/compat/_scons_dbm.py b/tools/scons/scons-local-3.0.5/SCons/compat/_scons_dbm.py new file mode 100755 index 0000000000..a57f105870 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/compat/_scons_dbm.py @@ -0,0 +1,45 @@ +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__doc__ = """ +dbm compatibility module for Python versions that don't have dbm. + +This does not not NOT (repeat, *NOT*) provide complete dbm functionality. +It's just a stub on which to hang just enough pieces of dbm functionality +that the whichdb.whichdb() implementstation in the various 2.X versions of +Python won't blow up even if dbm wasn't compiled in. +""" + +__revision__ = "src/engine/SCons/compat/_scons_dbm.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +class error(Exception): + pass + +def open(*args, **kw): + raise error() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/cpp.py b/tools/scons/scons-local-3.0.5/SCons/cpp.py new file mode 100755 index 0000000000..eb537e2349 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/cpp.py @@ -0,0 +1,595 @@ +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/cpp.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +__doc__ = """ +SCons C Pre-Processor module +""" +import SCons.compat + +import os +import re + +# +# First "subsystem" of regular expressions that we set up: +# +# Stuff to turn the C preprocessor directives in a file's contents into +# a list of tuples that we can process easily. +# + +# A table of regular expressions that fetch the arguments from the rest of +# a C preprocessor line. Different directives have different arguments +# that we want to fetch, using the regular expressions to which the lists +# of preprocessor directives map. +cpp_lines_dict = { + # Fetch the rest of a #if/#elif as one argument, + # with white space optional. + ('if', 'elif') : r'\s*(.+)', + + # Fetch the rest of a #ifdef/#ifndef as one argument, + # separated from the keyword by white space. + ('ifdef', 'ifndef',): r'\s+(.+)', + + # Fetch the rest of a #import/#include/#include_next line as one + # argument, with white space optional. + ('import', 'include', 'include_next',) + : r'\s*(.+)', + + # We don't care what comes after a #else or #endif line. + ('else', 'endif',) : '', + + # Fetch three arguments from a #define line: + # 1) The #defined keyword. + # 2) The optional parentheses and arguments (if it's a function-like + # macro, '' if it's not). + # 3) The expansion value. + ('define',) : r'\s+([_A-Za-z][_A-Za-z0-9_]*)(\([^)]*\))?\s*(.*)', + + # Fetch the #undefed keyword from a #undef line. + ('undef',) : r'\s+([_A-Za-z][A-Za-z0-9_]*)', +} + +# Create a table that maps each individual C preprocessor directive to +# the corresponding compiled regular expression that fetches the arguments +# we care about. +Table = {} +for op_list, expr in cpp_lines_dict.items(): + e = re.compile(expr) + for op in op_list: + Table[op] = e +del e +del op +del op_list + +# Create a list of the expressions we'll use to match all of the +# preprocessor directives. These are the same as the directives +# themselves *except* that we must use a negative lookahead assertion +# when matching "if" so it doesn't match the "if" in "ifdef" or "ifndef". +override = { + 'if' : 'if(?!n?def)', +} +l = [override.get(x, x) for x in list(Table.keys())] + + +# Turn the list of expressions into one big honkin' regular expression +# that will match all the preprocessor lines at once. This will return +# a list of tuples, one for each preprocessor line. The preprocessor +# directive will be the first element in each tuple, and the rest of +# the line will be the second element. +e = r'^\s*#\s*(' + '|'.join(l) + ')(.*)$' + +# And last but not least, compile the expression. +CPP_Expression = re.compile(e, re.M) + + + + +# +# Second "subsystem" of regular expressions that we set up: +# +# Stuff to translate a C preprocessor expression (as found on a #if or +# #elif line) into an equivalent Python expression that we can eval(). +# + +# A dictionary that maps the C representation of Boolean operators +# to their Python equivalents. +CPP_to_Python_Ops_Dict = { + '!' : ' not ', + '!=' : ' != ', + '&&' : ' and ', + '||' : ' or ', + '?' : ' and ', + ':' : ' or ', + '\r' : '', +} + +CPP_to_Python_Ops_Sub = lambda m: CPP_to_Python_Ops_Dict[m.group(0)] + +# We have to sort the keys by length so that longer expressions +# come *before* shorter expressions--in particular, "!=" must +# come before "!" in the alternation. Without this, the Python +# re module, as late as version 2.2.2, empirically matches the +# "!" in "!=" first, instead of finding the longest match. +# What's up with that? +l = sorted(list(CPP_to_Python_Ops_Dict.keys()), key=lambda a: len(a), reverse=True) + +# Turn the list of keys into one regular expression that will allow us +# to substitute all of the operators at once. +expr = '|'.join(map(re.escape, l)) + +# ...and compile the expression. +CPP_to_Python_Ops_Expression = re.compile(expr) + +# A separate list of expressions to be evaluated and substituted +# sequentially, not all at once. +CPP_to_Python_Eval_List = [ + [r'defined\s+(\w+)', '"\\1" in __dict__'], + [r'defined\s*\((\w+)\)', '"\\1" in __dict__'], + [r'/\*.*\*/', ''], + [r'/\*.*', ''], + [r'//.*', ''], + [r'(0x[0-9A-Fa-f]*)[UL]+', '\\1'], +] + +# Replace the string representations of the regular expressions in the +# list with compiled versions. +for l in CPP_to_Python_Eval_List: + l[0] = re.compile(l[0]) + +# Wrap up all of the above into a handy function. +def CPP_to_Python(s): + """ + Converts a C pre-processor expression into an equivalent + Python expression that can be evaluated. + """ + s = CPP_to_Python_Ops_Expression.sub(CPP_to_Python_Ops_Sub, s) + for expr, repl in CPP_to_Python_Eval_List: + s = expr.sub(repl, s) + return s + + + +del expr +del l +del override + + + +class FunctionEvaluator(object): + """ + Handles delayed evaluation of a #define function call. + """ + def __init__(self, name, args, expansion): + """ + Squirrels away the arguments and expansion value of a #define + macro function for later evaluation when we must actually expand + a value that uses it. + """ + self.name = name + self.args = function_arg_separator.split(args) + try: + expansion = expansion.split('##') + except AttributeError: + pass + self.expansion = expansion + def __call__(self, *values): + """ + Evaluates the expansion of a #define macro function called + with the specified values. + """ + if len(self.args) != len(values): + raise ValueError("Incorrect number of arguments to `%s'" % self.name) + # Create a dictionary that maps the macro arguments to the + # corresponding values in this "call." We'll use this when we + # eval() the expansion so that arguments will get expanded to + # the right values. + locals = {} + for k, v in zip(self.args, values): + locals[k] = v + + parts = [] + for s in self.expansion: + if not s in self.args: + s = repr(s) + parts.append(s) + statement = ' + '.join(parts) + + return eval(statement, globals(), locals) + + + +# Find line continuations. +line_continuations = re.compile('\\\\\r?\n') + +# Search for a "function call" macro on an expansion. Returns the +# two-tuple of the "function" name itself, and a string containing the +# arguments within the call parentheses. +function_name = re.compile(r'(\S+)\(([^)]*)\)') + +# Split a string containing comma-separated function call arguments into +# the separate arguments. +function_arg_separator = re.compile(r',\s*') + + + +class PreProcessor(object): + """ + The main workhorse class for handling C pre-processing. + """ + def __init__(self, current=os.curdir, cpppath=(), dict={}, all=0): + global Table + + cpppath = tuple(cpppath) + + self.searchpath = { + '"' : (current,) + cpppath, + '<' : cpppath + (current,), + } + + # Initialize our C preprocessor namespace for tracking the + # values of #defined keywords. We use this namespace to look + # for keywords on #ifdef/#ifndef lines, and to eval() the + # expressions on #if/#elif lines (after massaging them from C to + # Python). + self.cpp_namespace = dict.copy() + self.cpp_namespace['__dict__'] = self.cpp_namespace + + if all: + self.do_include = self.all_include + + # For efficiency, a dispatch table maps each C preprocessor + # directive (#if, #define, etc.) to the method that should be + # called when we see it. We accomodate state changes (#if, + # #ifdef, #ifndef) by pushing the current dispatch table on a + # stack and changing what method gets called for each relevant + # directive we might see next at this level (#else, #elif). + # #endif will simply pop the stack. + d = { + 'scons_current_file' : self.scons_current_file + } + for op in list(Table.keys()): + d[op] = getattr(self, 'do_' + op) + self.default_table = d + + # Controlling methods. + + def tupleize(self, contents): + """ + Turns the contents of a file into a list of easily-processed + tuples describing the CPP lines in the file. + + The first element of each tuple is the line's preprocessor + directive (#if, #include, #define, etc., minus the initial '#'). + The remaining elements are specific to the type of directive, as + pulled apart by the regular expression. + """ + global CPP_Expression, Table + contents = line_continuations.sub('', contents) + cpp_tuples = CPP_Expression.findall(contents) + return [(m[0],) + Table[m[0]].match(m[1]).groups() for m in cpp_tuples] + + def __call__(self, file): + """ + Pre-processes a file. + + This is the main public entry point. + """ + self.current_file = file + return self.process_contents(self.read_file(file), file) + + def process_contents(self, contents, fname=None): + """ + Pre-processes a file contents. + + This is the main internal entry point. + """ + self.stack = [] + self.dispatch_table = self.default_table.copy() + self.current_file = fname + self.tuples = self.tupleize(contents) + + self.initialize_result(fname) + while self.tuples: + t = self.tuples.pop(0) + # Uncomment to see the list of tuples being processed (e.g., + # to validate the CPP lines are being translated correctly). + #print(t) + self.dispatch_table[t[0]](t) + return self.finalize_result(fname) + + # Dispatch table stack manipulation methods. + + def save(self): + """ + Pushes the current dispatch table on the stack and re-initializes + the current dispatch table to the default. + """ + self.stack.append(self.dispatch_table) + self.dispatch_table = self.default_table.copy() + + def restore(self): + """ + Pops the previous dispatch table off the stack and makes it the + current one. + """ + try: self.dispatch_table = self.stack.pop() + except IndexError: pass + + # Utility methods. + + def do_nothing(self, t): + """ + Null method for when we explicitly want the action for a + specific preprocessor directive to do nothing. + """ + pass + + def scons_current_file(self, t): + self.current_file = t[1] + + def eval_expression(self, t): + """ + Evaluates a C preprocessor expression. + + This is done by converting it to a Python equivalent and + eval()ing it in the C preprocessor namespace we use to + track #define values. + """ + t = CPP_to_Python(' '.join(t[1:])) + try: return eval(t, self.cpp_namespace) + except (NameError, TypeError): return 0 + + def initialize_result(self, fname): + self.result = [fname] + + def finalize_result(self, fname): + return self.result[1:] + + def find_include_file(self, t): + """ + Finds the #include file for a given preprocessor tuple. + """ + fname = t[2] + for d in self.searchpath[t[1]]: + if d == os.curdir: + f = fname + else: + f = os.path.join(d, fname) + if os.path.isfile(f): + return f + return None + + def read_file(self, file): + with open(file) as f: + return f.read() + + # Start and stop processing include lines. + + def start_handling_includes(self, t=None): + """ + Causes the PreProcessor object to start processing #import, + #include and #include_next lines. + + This method will be called when a #if, #ifdef, #ifndef or #elif + evaluates True, or when we reach the #else in a #if, #ifdef, + #ifndef or #elif block where a condition already evaluated + False. + + """ + d = self.dispatch_table + p = self.stack[-1] if self.stack else self.default_table + + for k in ('import', 'include', 'include_next'): + d[k] = p[k] + + def stop_handling_includes(self, t=None): + """ + Causes the PreProcessor object to stop processing #import, + #include and #include_next lines. + + This method will be called when a #if, #ifdef, #ifndef or #elif + evaluates False, or when we reach the #else in a #if, #ifdef, + #ifndef or #elif block where a condition already evaluated True. + """ + d = self.dispatch_table + d['import'] = self.do_nothing + d['include'] = self.do_nothing + d['include_next'] = self.do_nothing + + # Default methods for handling all of the preprocessor directives. + # (Note that what actually gets called for a given directive at any + # point in time is really controlled by the dispatch_table.) + + def _do_if_else_condition(self, condition): + """ + Common logic for evaluating the conditions on #if, #ifdef and + #ifndef lines. + """ + self.save() + d = self.dispatch_table + if condition: + self.start_handling_includes() + d['elif'] = self.stop_handling_includes + d['else'] = self.stop_handling_includes + else: + self.stop_handling_includes() + d['elif'] = self.do_elif + d['else'] = self.start_handling_includes + + def do_ifdef(self, t): + """ + Default handling of a #ifdef line. + """ + self._do_if_else_condition(t[1] in self.cpp_namespace) + + def do_ifndef(self, t): + """ + Default handling of a #ifndef line. + """ + self._do_if_else_condition(t[1] not in self.cpp_namespace) + + def do_if(self, t): + """ + Default handling of a #if line. + """ + self._do_if_else_condition(self.eval_expression(t)) + + def do_elif(self, t): + """ + Default handling of a #elif line. + """ + d = self.dispatch_table + if self.eval_expression(t): + self.start_handling_includes() + d['elif'] = self.stop_handling_includes + d['else'] = self.stop_handling_includes + + def do_else(self, t): + """ + Default handling of a #else line. + """ + pass + + def do_endif(self, t): + """ + Default handling of a #endif line. + """ + self.restore() + + def do_define(self, t): + """ + Default handling of a #define line. + """ + _, name, args, expansion = t + try: + expansion = int(expansion) + except (TypeError, ValueError): + pass + if args: + evaluator = FunctionEvaluator(name, args[1:-1], expansion) + self.cpp_namespace[name] = evaluator + else: + self.cpp_namespace[name] = expansion + + def do_undef(self, t): + """ + Default handling of a #undef line. + """ + try: del self.cpp_namespace[t[1]] + except KeyError: pass + + def do_import(self, t): + """ + Default handling of a #import line. + """ + # XXX finish this -- maybe borrow/share logic from do_include()...? + pass + + def do_include(self, t): + """ + Default handling of a #include line. + """ + t = self.resolve_include(t) + include_file = self.find_include_file(t) + if include_file: + #print("include_file =", include_file) + self.result.append(include_file) + contents = self.read_file(include_file) + new_tuples = [('scons_current_file', include_file)] + \ + self.tupleize(contents) + \ + [('scons_current_file', self.current_file)] + self.tuples[:] = new_tuples + self.tuples + + # Date: Tue, 22 Nov 2005 20:26:09 -0500 + # From: Stefan Seefeld + # + # By the way, #include_next is not the same as #include. The difference + # being that #include_next starts its search in the path following the + # path that let to the including file. In other words, if your system + # include paths are ['/foo', '/bar'], and you are looking at a header + # '/foo/baz.h', it might issue an '#include_next ' which would + # correctly resolve to '/bar/baz.h' (if that exists), but *not* see + # '/foo/baz.h' again. See http://www.delorie.com/gnu/docs/gcc/cpp_11.html + # for more reasoning. + # + # I have no idea in what context 'import' might be used. + + # XXX is #include_next really the same as #include ? + do_include_next = do_include + + # Utility methods for handling resolution of include files. + + def resolve_include(self, t): + """Resolve a tuple-ized #include line. + + This handles recursive expansion of values without "" or <> + surrounding the name until an initial " or < is found, to handle + + #include FILE + + where FILE is a #define somewhere else.""" + + s = t[1] + while not s[0] in '<"': + #print("s =", s) + try: + s = self.cpp_namespace[s] + except KeyError: + m = function_name.search(s) + s = self.cpp_namespace[m.group(1)] + if callable(s): + args = function_arg_separator.split(m.group(2)) + s = s(*args) + if not s: + return None + return (t[0], s[0], s[1:-1]) + + def all_include(self, t): + """ + """ + self.result.append(self.resolve_include(t)) + +class DumbPreProcessor(PreProcessor): + """A preprocessor that ignores all #if/#elif/#else/#endif directives + and just reports back *all* of the #include files (like the classic + SCons scanner did). + + This is functionally equivalent to using a regular expression to + find all of the #include lines, only slower. It exists mainly as + an example of how the main PreProcessor class can be sub-classed + to tailor its behavior. + """ + def __init__(self, *args, **kw): + PreProcessor.__init__(self, *args, **kw) + d = self.default_table + for func in ['if', 'elif', 'else', 'endif', 'ifdef', 'ifndef']: + d[func] = d[func] = self.do_nothing + +del __revision__ + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/dblite.py b/tools/scons/scons-local-3.0.5/SCons/dblite.py new file mode 100755 index 0000000000..14bd93dc32 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/dblite.py @@ -0,0 +1,290 @@ +# dblite.py module contributed by Ralf W. Grosse-Kunstleve. +# Extended for Unicode by Steven Knight. +from __future__ import print_function + +import os +import pickle +import shutil +import time + +from SCons.compat import PICKLE_PROTOCOL + +keep_all_files = 00000 +ignore_corrupt_dbfiles = 0 + + +def corruption_warning(filename): + print("Warning: Discarding corrupt database:", filename) + + +try: + unicode +except NameError: + def is_string(s): + return isinstance(s, str) +else: + def is_string(s): + return type(s) in (str, unicode) + + +def is_bytes(s): + return isinstance(s, bytes) + + +try: + unicode('a') +except NameError: + def unicode(s): + return s + +dblite_suffix = '.dblite' + +# TODO: Does commenting this out break switching from py2/3? +# if bytes is not str: +# dblite_suffix += '.p3' +tmp_suffix = '.tmp' + + +class dblite(object): + """ + Squirrel away references to the functions in various modules + that we'll use when our __del__() method calls our sync() method + during shutdown. We might get destroyed when Python is in the midst + of tearing down the different modules we import in an essentially + arbitrary order, and some of the various modules's global attributes + may already be wiped out from under us. + + See the discussion at: + http://mail.python.org/pipermail/python-bugs-list/2003-March/016877.html + """ + + _open = open + _pickle_dump = staticmethod(pickle.dump) + _pickle_protocol = PICKLE_PROTOCOL + _os_chmod = os.chmod + + try: + _os_chown = os.chown + except AttributeError: + _os_chown = None + + _os_rename = os.rename + _os_unlink = os.unlink + _shutil_copyfile = shutil.copyfile + _time_time = time.time + + def __init__(self, file_base_name, flag, mode): + assert flag in (None, "r", "w", "c", "n") + if flag is None: + flag = "r" + + base, ext = os.path.splitext(file_base_name) + if ext == dblite_suffix: + # There's already a suffix on the file name, don't add one. + self._file_name = file_base_name + self._tmp_name = base + tmp_suffix + else: + self._file_name = file_base_name + dblite_suffix + self._tmp_name = file_base_name + tmp_suffix + + self._flag = flag + self._mode = mode + self._dict = {} + self._needs_sync = 00000 + + if self._os_chown is not None and (os.geteuid() == 0 or os.getuid() == 0): + # running as root; chown back to current owner/group when done + try: + statinfo = os.stat(self._file_name) + self._chown_to = statinfo.st_uid + self._chgrp_to = statinfo.st_gid + except OSError as e: + # db file doesn't exist yet. + # Check os.environ for SUDO_UID, use if set + self._chown_to = int(os.environ.get('SUDO_UID', -1)) + self._chgrp_to = int(os.environ.get('SUDO_GID', -1)) + else: + self._chown_to = -1 # don't chown + self._chgrp_to = -1 # don't chgrp + + if self._flag == "n": + with self._open(self._file_name, "wb", self._mode): + pass # just make sure it exists + else: + try: + f = self._open(self._file_name, "rb") + except IOError as e: + if self._flag != "c": + raise e + with self._open(self._file_name, "wb", self._mode): + pass # just make sure it exists + else: + p = f.read() + f.close() + if len(p) > 0: + try: + if bytes is not str: + self._dict = pickle.loads(p, encoding='bytes') + else: + self._dict = pickle.loads(p) + except (pickle.UnpicklingError, EOFError, KeyError): + # Note how we catch KeyErrors too here, which might happen + # when we don't have cPickle available (default pickle + # throws it). + if (ignore_corrupt_dbfiles == 0): raise + if (ignore_corrupt_dbfiles == 1): + corruption_warning(self._file_name) + + def close(self): + if self._needs_sync: + self.sync() + + def __del__(self): + self.close() + + def sync(self): + self._check_writable() + f = self._open(self._tmp_name, "wb", self._mode) + self._pickle_dump(self._dict, f, self._pickle_protocol) + f.close() + + # Windows doesn't allow renaming if the file exists, so unlink + # it first, chmod'ing it to make sure we can do so. On UNIX, we + # may not be able to chmod the file if it's owned by someone else + # (e.g. from a previous run as root). We should still be able to + # unlink() the file if the directory's writable, though, so ignore + # any OSError exception thrown by the chmod() call. + try: + self._os_chmod(self._file_name, 0o777) + except OSError: + pass + self._os_unlink(self._file_name) + self._os_rename(self._tmp_name, self._file_name) + if self._os_chown is not None and self._chown_to > 0: # don't chown to root or -1 + try: + self._os_chown(self._file_name, self._chown_to, self._chgrp_to) + except OSError: + pass + self._needs_sync = 00000 + if (keep_all_files): + self._shutil_copyfile( + self._file_name, + self._file_name + "_" + str(int(self._time_time()))) + + def _check_writable(self): + if (self._flag == "r"): + raise IOError("Read-only database: %s" % self._file_name) + + def __getitem__(self, key): + return self._dict[key] + + def __setitem__(self, key, value): + self._check_writable() + if (not is_string(key)): + raise TypeError("key `%s' must be a string but is %s" % (key, type(key))) + if (not is_bytes(value)): + raise TypeError("value `%s' must be a bytes but is %s" % (value, type(value))) + self._dict[key] = value + self._needs_sync = 0o001 + + def keys(self): + return list(self._dict.keys()) + + def has_key(self, key): + return key in self._dict + + def __contains__(self, key): + return key in self._dict + + def iterkeys(self): + # Wrapping name in () prevents fixer from "fixing" this + return (self._dict.iterkeys)() + + __iter__ = iterkeys + + def __len__(self): + return len(self._dict) + + +def open(file, flag=None, mode=0o666): + return dblite(file, flag, mode) + + +def _exercise(): + db = open("tmp", "n") + assert len(db) == 0 + db["foo"] = "bar" + assert db["foo"] == "bar" + db[unicode("ufoo")] = unicode("ubar") + assert db[unicode("ufoo")] == unicode("ubar") + db.sync() + db = open("tmp", "c") + assert len(db) == 2, len(db) + assert db["foo"] == "bar" + db["bar"] = "foo" + assert db["bar"] == "foo" + db[unicode("ubar")] = unicode("ufoo") + assert db[unicode("ubar")] == unicode("ufoo") + db.sync() + db = open("tmp", "r") + assert len(db) == 4, len(db) + assert db["foo"] == "bar" + assert db["bar"] == "foo" + assert db[unicode("ufoo")] == unicode("ubar") + assert db[unicode("ubar")] == unicode("ufoo") + try: + db.sync() + except IOError as e: + assert str(e) == "Read-only database: tmp.dblite" + else: + raise RuntimeError("IOError expected.") + db = open("tmp", "w") + assert len(db) == 4 + db["ping"] = "pong" + db.sync() + try: + db[(1, 2)] = "tuple" + except TypeError as e: + assert str(e) == "key `(1, 2)' must be a string but is ", str(e) + else: + raise RuntimeError("TypeError exception expected") + try: + db["list"] = [1, 2] + except TypeError as e: + assert str(e) == "value `[1, 2]' must be a string but is ", str(e) + else: + raise RuntimeError("TypeError exception expected") + db = open("tmp", "r") + assert len(db) == 5 + db = open("tmp", "n") + assert len(db) == 0 + dblite._open("tmp.dblite", "w") + db = open("tmp", "r") + dblite._open("tmp.dblite", "w").write("x") + try: + db = open("tmp", "r") + except pickle.UnpicklingError: + pass + else: + raise RuntimeError("pickle exception expected.") + global ignore_corrupt_dbfiles + ignore_corrupt_dbfiles = 2 + db = open("tmp", "r") + assert len(db) == 0 + os.unlink("tmp.dblite") + try: + db = open("tmp", "w") + except IOError as e: + assert str(e) == "[Errno 2] No such file or directory: 'tmp.dblite'", str(e) + else: + raise RuntimeError("IOError expected.") + + +if (__name__ == "__main__"): + _exercise() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-local-3.0.5/SCons/exitfuncs.py b/tools/scons/scons-local-3.0.5/SCons/exitfuncs.py new file mode 100755 index 0000000000..e1b9382588 --- /dev/null +++ b/tools/scons/scons-local-3.0.5/SCons/exitfuncs.py @@ -0,0 +1,64 @@ +"""SCons.exitfuncs + +Register functions which are executed when SCons exits for any reason. + +""" + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/exitfuncs.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + + +import atexit + +_exithandlers = [] +def _run_exitfuncs(): + """run any registered exit functions + + _exithandlers is traversed in reverse order so functions are executed + last in, first out. + """ + + while _exithandlers: + func, targs, kargs = _exithandlers.pop() + func(*targs, **kargs) + +def register(func, *targs, **kargs): + """register a function to be executed upon normal program termination + + func - function to be called at exit + targs - optional arguments to pass to func + kargs - optional keyword arguments to pass to func + """ + _exithandlers.append((func, targs, kargs)) + + +# make our exit function get run by python when it exits +atexit.register(_run_exitfuncs) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons-time.py b/tools/scons/scons-time.py new file mode 100755 index 0000000000..26ddd77f51 --- /dev/null +++ b/tools/scons/scons-time.py @@ -0,0 +1,1510 @@ +#!/usr/bin/env python +# +# scons-time - run SCons timings and collect statistics +# +# A script for running a configuration through SCons with a standard +# set of invocations to collect timing and memory statistics and to +# capture the results in a consistent set of output files for display +# and analysis. +# + +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from __future__ import division, print_function + +__revision__ = "src/script/scons-time.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +import getopt +import glob +import os +import re +import shutil +import sys +import tempfile +import time + +def make_temp_file(**kw): + try: + result = tempfile.mktemp(**kw) + result = os.path.realpath(result) + except TypeError: + try: + save_template = tempfile.template + prefix = kw['prefix'] + del kw['prefix'] + tempfile.template = prefix + result = tempfile.mktemp(**kw) + finally: + tempfile.template = save_template + return result + +def HACK_for_exec(cmd, *args): + """ + For some reason, Python won't allow an exec() within a function + that also declares an internal function (including lambda functions). + This function is a hack that calls exec() in a function with no + internal functions. + """ + if not args: exec(cmd) + elif len(args) == 1: exec(cmd, args[0]) + else: exec(cmd, args[0], args[1]) + +class Plotter(object): + def increment_size(self, largest): + """ + Return the size of each horizontal increment line for a specified + maximum value. This returns a value that will provide somewhere + between 5 and 9 horizontal lines on the graph, on some set of + boundaries that are multiples of 10/100/1000/etc. + """ + i = largest // 5 + if not i: + return largest + multiplier = 1 + while i >= 10: + i = i // 10 + multiplier = multiplier * 10 + return i * multiplier + + def max_graph_value(self, largest): + # Round up to next integer. + largest = int(largest) + 1 + increment = self.increment_size(largest) + return ((largest + increment - 1) // increment) * increment + +class Line(object): + def __init__(self, points, type, title, label, comment, fmt="%s %s"): + self.points = points + self.type = type + self.title = title + self.label = label + self.comment = comment + self.fmt = fmt + + def print_label(self, inx, x, y): + if self.label: + print('set label %s "%s" at %0.1f,%0.1f right' % (inx, self.label, x, y)) + + def plot_string(self): + if self.title: + title_string = 'title "%s"' % self.title + else: + title_string = 'notitle' + return "'-' %s with lines lt %s" % (title_string, self.type) + + def print_points(self, fmt=None): + if fmt is None: + fmt = self.fmt + if self.comment: + print('# %s' % self.comment) + for x, y in self.points: + # If y is None, it usually represents some kind of break + # in the line's index number. We might want to represent + # this some way rather than just drawing the line straight + # between the two points on either side. + if not y is None: + print(fmt % (x, y)) + print('e') + + def get_x_values(self): + return [ p[0] for p in self.points ] + + def get_y_values(self): + return [ p[1] for p in self.points ] + +class Gnuplotter(Plotter): + + def __init__(self, title, key_location): + self.lines = [] + self.title = title + self.key_location = key_location + + def line(self, points, type, title=None, label=None, comment=None, fmt='%s %s'): + if points: + line = Line(points, type, title, label, comment, fmt) + self.lines.append(line) + + def plot_string(self, line): + return line.plot_string() + + def vertical_bar(self, x, type, label, comment): + if self.get_min_x() <= x <= self.get_max_x(): + points = [(x, 0), (x, self.max_graph_value(self.get_max_y()))] + self.line(points, type, label, comment) + + def get_all_x_values(self): + result = [] + for line in self.lines: + result.extend(line.get_x_values()) + return [r for r in result if not r is None] + + def get_all_y_values(self): + result = [] + for line in self.lines: + result.extend(line.get_y_values()) + return [r for r in result if not r is None] + + def get_min_x(self): + try: + return self.min_x + except AttributeError: + try: + self.min_x = min(self.get_all_x_values()) + except ValueError: + self.min_x = 0 + return self.min_x + + def get_max_x(self): + try: + return self.max_x + except AttributeError: + try: + self.max_x = max(self.get_all_x_values()) + except ValueError: + self.max_x = 0 + return self.max_x + + def get_min_y(self): + try: + return self.min_y + except AttributeError: + try: + self.min_y = min(self.get_all_y_values()) + except ValueError: + self.min_y = 0 + return self.min_y + + def get_max_y(self): + try: + return self.max_y + except AttributeError: + try: + self.max_y = max(self.get_all_y_values()) + except ValueError: + self.max_y = 0 + return self.max_y + + def draw(self): + + if not self.lines: + return + + if self.title: + print('set title "%s"' % self.title) + print('set key %s' % self.key_location) + + min_y = self.get_min_y() + max_y = self.max_graph_value(self.get_max_y()) + incr = (max_y - min_y) / 10.0 + start = min_y + (max_y / 2.0) + (2.0 * incr) + position = [ start - (i * incr) for i in range(5) ] + + inx = 1 + for line in self.lines: + line.print_label(inx, line.points[0][0]-1, + position[(inx-1) % len(position)]) + inx += 1 + + plot_strings = [ self.plot_string(l) for l in self.lines ] + print('plot ' + ', \\\n '.join(plot_strings)) + + for line in self.lines: + line.print_points() + + + +def untar(fname): + import tarfile + tar = tarfile.open(name=fname, mode='r') + for tarinfo in tar: + tar.extract(tarinfo) + tar.close() + +def unzip(fname): + import zipfile + zf = zipfile.ZipFile(fname, 'r') + for name in zf.namelist(): + dir = os.path.dirname(name) + try: + os.makedirs(dir) + except: + pass + open(name, 'wb').write(zf.read(name)) + +def read_tree(dir): + for dirpath, dirnames, filenames in os.walk(dir): + for fn in filenames: + fn = os.path.join(dirpath, fn) + if os.path.isfile(fn): + open(fn, 'rb').read() + +def redirect_to_file(command, log): + return '%s > %s 2>&1' % (command, log) + +def tee_to_file(command, log): + return '%s 2>&1 | tee %s' % (command, log) + + + +class SConsTimer(object): + """ + Usage: scons-time SUBCOMMAND [ARGUMENTS] + Type "scons-time help SUBCOMMAND" for help on a specific subcommand. + + Available subcommands: + func Extract test-run data for a function + help Provides help + mem Extract --debug=memory data from test runs + obj Extract --debug=count data from test runs + time Extract --debug=time data from test runs + run Runs a test configuration + """ + + name = 'scons-time' + name_spaces = ' '*len(name) + + def makedict(**kw): + return kw + + default_settings = makedict( + aegis = 'aegis', + aegis_project = None, + chdir = None, + config_file = None, + initial_commands = [], + key_location = 'bottom left', + orig_cwd = os.getcwd(), + outdir = None, + prefix = '', + python = '"%s"' % sys.executable, + redirect = redirect_to_file, + scons = None, + scons_flags = '--debug=count --debug=memory --debug=time --debug=memoizer', + scons_lib_dir = None, + scons_wrapper = None, + startup_targets = '--help', + subdir = None, + subversion_url = None, + svn = 'svn', + svn_co_flag = '-q', + tar = 'tar', + targets = '', + targets0 = None, + targets1 = None, + targets2 = None, + title = None, + unzip = 'unzip', + verbose = False, + vertical_bars = [], + + unpack_map = { + '.tar.gz' : (untar, '%(tar)s xzf %%s'), + '.tgz' : (untar, '%(tar)s xzf %%s'), + '.tar' : (untar, '%(tar)s xf %%s'), + '.zip' : (unzip, '%(unzip)s %%s'), + }, + ) + + run_titles = [ + 'Startup', + 'Full build', + 'Up-to-date build', + ] + + run_commands = [ + '%(python)s %(scons_wrapper)s %(scons_flags)s --profile=%(prof0)s %(targets0)s', + '%(python)s %(scons_wrapper)s %(scons_flags)s --profile=%(prof1)s %(targets1)s', + '%(python)s %(scons_wrapper)s %(scons_flags)s --profile=%(prof2)s %(targets2)s', + ] + + stages = [ + 'pre-read', + 'post-read', + 'pre-build', + 'post-build', + ] + + stage_strings = { + 'pre-read' : 'Memory before reading SConscript files:', + 'post-read' : 'Memory after reading SConscript files:', + 'pre-build' : 'Memory before building targets:', + 'post-build' : 'Memory after building targets:', + } + + memory_string_all = 'Memory ' + + default_stage = stages[-1] + + time_strings = { + 'total' : 'Total build time', + 'SConscripts' : 'Total SConscript file execution time', + 'SCons' : 'Total SCons execution time', + 'commands' : 'Total command execution time', + } + + time_string_all = 'Total .* time' + + # + + def __init__(self): + self.__dict__.update(self.default_settings) + + # Functions for displaying and executing commands. + + def subst(self, x, dictionary): + try: + return x % dictionary + except TypeError: + # x isn't a string (it's probably a Python function), + # so just return it. + return x + + def subst_variables(self, command, dictionary): + """ + Substitutes (via the format operator) the values in the specified + dictionary into the specified command. + + The command can be an (action, string) tuple. In all cases, we + perform substitution on strings and don't worry if something isn't + a string. (It's probably a Python function to be executed.) + """ + try: + command + '' + except TypeError: + action = command[0] + string = command[1] + args = command[2:] + else: + action = command + string = action + args = (()) + action = self.subst(action, dictionary) + string = self.subst(string, dictionary) + return (action, string, args) + + def _do_not_display(self, msg, *args): + pass + + def display(self, msg, *args): + """ + Displays the specified message. + + Each message is prepended with a standard prefix of our name + plus the time. + """ + if callable(msg): + msg = msg(*args) + else: + msg = msg % args + if msg is None: + return + fmt = '%s[%s]: %s\n' + sys.stdout.write(fmt % (self.name, time.strftime('%H:%M:%S'), msg)) + + def _do_not_execute(self, action, *args): + pass + + def execute(self, action, *args): + """ + Executes the specified action. + + The action is called if it's a callable Python function, and + otherwise passed to os.system(). + """ + if callable(action): + action(*args) + else: + os.system(action % args) + + def run_command_list(self, commands, dict): + """ + Executes a list of commands, substituting values from the + specified dictionary. + """ + commands = [ self.subst_variables(c, dict) for c in commands ] + for action, string, args in commands: + self.display(string, *args) + sys.stdout.flush() + status = self.execute(action, *args) + if status: + sys.exit(status) + + def log_display(self, command, log): + command = self.subst(command, self.__dict__) + if log: + command = self.redirect(command, log) + return command + + def log_execute(self, command, log): + command = self.subst(command, self.__dict__) + output = os.popen(command).read() + if self.verbose: + sys.stdout.write(output) + # TODO: Figure out + # Not sure we need to write binary here + open(log, 'w').write(output) + + # + + def archive_splitext(self, path): + """ + Splits an archive name into a filename base and extension. + + This is like os.path.splitext() (which it calls) except that it + also looks for '.tar.gz' and treats it as an atomic extensions. + """ + if path.endswith('.tar.gz'): + return path[:-7], path[-7:] + else: + return os.path.splitext(path) + + def args_to_files(self, args, tail=None): + """ + Takes a list of arguments, expands any glob patterns, and + returns the last "tail" files from the list. + """ + files = [] + for a in args: + files.extend(sorted(glob.glob(a))) + + if tail: + files = files[-tail:] + + return files + + def ascii_table(self, files, columns, + line_function, file_function=lambda x: x, + *args, **kw): + + header_fmt = ' '.join(['%12s'] * len(columns)) + line_fmt = header_fmt + ' %s' + + print(header_fmt % columns) + + for file in files: + t = line_function(file, *args, **kw) + if t is None: + t = [] + diff = len(columns) - len(t) + if diff > 0: + t += [''] * diff + t.append(file_function(file)) + print(line_fmt % tuple(t)) + + def collect_results(self, files, function, *args, **kw): + results = {} + + for file in files: + base = os.path.splitext(file)[0] + run, index = base.split('-')[-2:] + + run = int(run) + index = int(index) + + value = function(file, *args, **kw) + + try: + r = results[index] + except KeyError: + r = [] + results[index] = r + r.append((run, value)) + + return results + + def doc_to_help(self, obj): + """ + Translates an object's __doc__ string into help text. + + This strips a consistent number of spaces from each line in the + help text, essentially "outdenting" the text to the left-most + column. + """ + doc = obj.__doc__ + if doc is None: + return '' + return self.outdent(doc) + + def find_next_run_number(self, dir, prefix): + """ + Returns the next run number in a directory for the specified prefix. + + Examines the contents the specified directory for files with the + specified prefix, extracts the run numbers from each file name, + and returns the next run number after the largest it finds. + """ + x = re.compile(re.escape(prefix) + '-([0-9]+).*') + matches = [x.match(e) for e in os.listdir(dir)] + matches = [_f for _f in matches if _f] + if not matches: + return 0 + run_numbers = [int(m.group(1)) for m in matches] + return int(max(run_numbers)) + 1 + + def gnuplot_results(self, results, fmt='%s %.3f'): + """ + Prints out a set of results in Gnuplot format. + """ + gp = Gnuplotter(self.title, self.key_location) + + for i in sorted(results.keys()): + try: + t = self.run_titles[i] + except IndexError: + t = '??? %s ???' % i + results[i].sort() + gp.line(results[i], i+1, t, None, t, fmt=fmt) + + for bar_tuple in self.vertical_bars: + try: + x, type, label, comment = bar_tuple + except ValueError: + x, type, label = bar_tuple + comment = label + gp.vertical_bar(x, type, label, comment) + + gp.draw() + + def logfile_name(self, invocation): + """ + Returns the absolute path of a log file for the specificed + invocation number. + """ + name = self.prefix_run + '-%d.log' % invocation + return os.path.join(self.outdir, name) + + def outdent(self, s): + """ + Strip as many spaces from each line as are found at the beginning + of the first line in the list. + """ + lines = s.split('\n') + if lines[0] == '': + lines = lines[1:] + spaces = re.match(' *', lines[0]).group(0) + def strip_initial_spaces(l, s=spaces): + if l.startswith(spaces): + l = l[len(spaces):] + return l + return '\n'.join([ strip_initial_spaces(l) for l in lines ]) + '\n' + + def profile_name(self, invocation): + """ + Returns the absolute path of a profile file for the specified + invocation number. + """ + name = self.prefix_run + '-%d.prof' % invocation + return os.path.join(self.outdir, name) + + def set_env(self, key, value): + os.environ[key] = value + + # + + def get_debug_times(self, file, time_string=None): + """ + Fetch times from the --debug=time strings in the specified file. + """ + if time_string is None: + search_string = self.time_string_all + else: + search_string = time_string + contents = open(file).read() + if not contents: + sys.stderr.write('file %s has no contents!\n' % repr(file)) + return None + result = re.findall(r'%s: ([\d\.]*)' % search_string, contents)[-4:] + result = [ float(r) for r in result ] + if not time_string is None: + try: + result = result[0] + except IndexError: + sys.stderr.write('file %s has no results!\n' % repr(file)) + return None + return result + + def get_function_profile(self, file, function): + """ + Returns the file, line number, function name, and cumulative time. + """ + try: + import pstats + except ImportError as e: + sys.stderr.write('%s: func: %s\n' % (self.name, e)) + sys.stderr.write('%s This version of Python is missing the profiler.\n' % self.name_spaces) + sys.stderr.write('%s Cannot use the "func" subcommand.\n' % self.name_spaces) + sys.exit(1) + statistics = pstats.Stats(file).stats + matches = [ e for e in statistics.items() if e[0][2] == function ] + r = matches[0] + return r[0][0], r[0][1], r[0][2], r[1][3] + + def get_function_time(self, file, function): + """ + Returns just the cumulative time for the specified function. + """ + return self.get_function_profile(file, function)[3] + + def get_memory(self, file, memory_string=None): + """ + Returns a list of integers of the amount of memory used. The + default behavior is to return all the stages. + """ + if memory_string is None: + search_string = self.memory_string_all + else: + search_string = memory_string + lines = open(file).readlines() + lines = [ l for l in lines if l.startswith(search_string) ][-4:] + result = [ int(l.split()[-1]) for l in lines[-4:] ] + if len(result) == 1: + result = result[0] + return result + + def get_object_counts(self, file, object_name, index=None): + """ + Returns the counts of the specified object_name. + """ + object_string = ' ' + object_name + '\n' + lines = open(file).readlines() + line = [ l for l in lines if l.endswith(object_string) ][0] + result = [ int(field) for field in line.split()[:4] ] + if index is not None: + result = result[index] + return result + + # + + command_alias = {} + + def execute_subcommand(self, argv): + """ + Executes the do_*() function for the specified subcommand (argv[0]). + """ + if not argv: + return + cmdName = self.command_alias.get(argv[0], argv[0]) + try: + func = getattr(self, 'do_' + cmdName) + except AttributeError: + return self.default(argv) + try: + return func(argv) + except TypeError as e: + sys.stderr.write("%s %s: %s\n" % (self.name, cmdName, e)) + import traceback + traceback.print_exc(file=sys.stderr) + sys.stderr.write("Try '%s help %s'\n" % (self.name, cmdName)) + + def default(self, argv): + """ + The default behavior for an unknown subcommand. Prints an + error message and exits. + """ + sys.stderr.write('%s: Unknown subcommand "%s".\n' % (self.name, argv[0])) + sys.stderr.write('Type "%s help" for usage.\n' % self.name) + sys.exit(1) + + # + + def do_help(self, argv): + """ + """ + if argv[1:]: + for arg in argv[1:]: + try: + func = getattr(self, 'do_' + arg) + except AttributeError: + sys.stderr.write('%s: No help for "%s"\n' % (self.name, arg)) + else: + try: + help = getattr(self, 'help_' + arg) + except AttributeError: + sys.stdout.write(self.doc_to_help(func)) + sys.stdout.flush() + else: + help() + else: + doc = self.doc_to_help(self.__class__) + if doc: + sys.stdout.write(doc) + sys.stdout.flush() + return None + + # + + def help_func(self): + help = """\ + Usage: scons-time func [OPTIONS] FILE [...] + + -C DIR, --chdir=DIR Change to DIR before looking for files + -f FILE, --file=FILE Read configuration from specified FILE + --fmt=FORMAT, --format=FORMAT Print data in specified FORMAT + --func=NAME, --function=NAME Report time for function NAME + -h, --help Print this help and exit + -p STRING, --prefix=STRING Use STRING as log file/profile prefix + -t NUMBER, --tail=NUMBER Only report the last NUMBER files + --title=TITLE Specify the output plot TITLE + """ + sys.stdout.write(self.outdent(help)) + sys.stdout.flush() + + def do_func(self, argv): + """ + """ + format = 'ascii' + function_name = '_main' + tail = None + + short_opts = '?C:f:hp:t:' + + long_opts = [ + 'chdir=', + 'file=', + 'fmt=', + 'format=', + 'func=', + 'function=', + 'help', + 'prefix=', + 'tail=', + 'title=', + ] + + opts, args = getopt.getopt(argv[1:], short_opts, long_opts) + + for o, a in opts: + if o in ('-C', '--chdir'): + self.chdir = a + elif o in ('-f', '--file'): + self.config_file = a + elif o in ('--fmt', '--format'): + format = a + elif o in ('--func', '--function'): + function_name = a + elif o in ('-?', '-h', '--help'): + self.do_help(['help', 'func']) + sys.exit(0) + elif o in ('--max',): + max_time = int(a) + elif o in ('-p', '--prefix'): + self.prefix = a + elif o in ('-t', '--tail'): + tail = int(a) + elif o in ('--title',): + self.title = a + + if self.config_file: + with open(self.config_file, 'r') as f: + config = f.read() + exec(config, self.__dict__) + + if self.chdir: + os.chdir(self.chdir) + + if not args: + + pattern = '%s*.prof' % self.prefix + args = self.args_to_files([pattern], tail) + + if not args: + if self.chdir: + directory = self.chdir + else: + directory = os.getcwd() + + sys.stderr.write('%s: func: No arguments specified.\n' % self.name) + sys.stderr.write('%s No %s*.prof files found in "%s".\n' % (self.name_spaces, self.prefix, directory)) + sys.stderr.write('%s Type "%s help func" for help.\n' % (self.name_spaces, self.name)) + sys.exit(1) + + else: + + args = self.args_to_files(args, tail) + + cwd_ = os.getcwd() + os.sep + + if format == 'ascii': + + for file in args: + try: + f, line, func, time = \ + self.get_function_profile(file, function_name) + except ValueError as e: + sys.stderr.write("%s: func: %s: %s\n" % + (self.name, file, e)) + else: + if f.startswith(cwd_): + f = f[len(cwd_):] + print("%.3f %s:%d(%s)" % (time, f, line, func)) + + elif format == 'gnuplot': + + results = self.collect_results(args, self.get_function_time, + function_name) + + self.gnuplot_results(results) + + else: + + sys.stderr.write('%s: func: Unknown format "%s".\n' % (self.name, format)) + sys.exit(1) + + # + + def help_mem(self): + help = """\ + Usage: scons-time mem [OPTIONS] FILE [...] + + -C DIR, --chdir=DIR Change to DIR before looking for files + -f FILE, --file=FILE Read configuration from specified FILE + --fmt=FORMAT, --format=FORMAT Print data in specified FORMAT + -h, --help Print this help and exit + -p STRING, --prefix=STRING Use STRING as log file/profile prefix + --stage=STAGE Plot memory at the specified stage: + pre-read, post-read, pre-build, + post-build (default: post-build) + -t NUMBER, --tail=NUMBER Only report the last NUMBER files + --title=TITLE Specify the output plot TITLE + """ + sys.stdout.write(self.outdent(help)) + sys.stdout.flush() + + def do_mem(self, argv): + + format = 'ascii' + logfile_path = lambda x: x + stage = self.default_stage + tail = None + + short_opts = '?C:f:hp:t:' + + long_opts = [ + 'chdir=', + 'file=', + 'fmt=', + 'format=', + 'help', + 'prefix=', + 'stage=', + 'tail=', + 'title=', + ] + + opts, args = getopt.getopt(argv[1:], short_opts, long_opts) + + for o, a in opts: + if o in ('-C', '--chdir'): + self.chdir = a + elif o in ('-f', '--file'): + self.config_file = a + elif o in ('--fmt', '--format'): + format = a + elif o in ('-?', '-h', '--help'): + self.do_help(['help', 'mem']) + sys.exit(0) + elif o in ('-p', '--prefix'): + self.prefix = a + elif o in ('--stage',): + if not a in self.stages: + sys.stderr.write('%s: mem: Unrecognized stage "%s".\n' % (self.name, a)) + sys.exit(1) + stage = a + elif o in ('-t', '--tail'): + tail = int(a) + elif o in ('--title',): + self.title = a + + if self.config_file: + with open(self.config_file, 'r') as f: + config = f.read() + HACK_for_exec(config, self.__dict__) + + if self.chdir: + os.chdir(self.chdir) + logfile_path = lambda x: os.path.join(self.chdir, x) + + if not args: + + pattern = '%s*.log' % self.prefix + args = self.args_to_files([pattern], tail) + + if not args: + if self.chdir: + directory = self.chdir + else: + directory = os.getcwd() + + sys.stderr.write('%s: mem: No arguments specified.\n' % self.name) + sys.stderr.write('%s No %s*.log files found in "%s".\n' % (self.name_spaces, self.prefix, directory)) + sys.stderr.write('%s Type "%s help mem" for help.\n' % (self.name_spaces, self.name)) + sys.exit(1) + + else: + + args = self.args_to_files(args, tail) + + cwd_ = os.getcwd() + os.sep + + if format == 'ascii': + + self.ascii_table(args, tuple(self.stages), self.get_memory, logfile_path) + + elif format == 'gnuplot': + + results = self.collect_results(args, self.get_memory, + self.stage_strings[stage]) + + self.gnuplot_results(results) + + else: + + sys.stderr.write('%s: mem: Unknown format "%s".\n' % (self.name, format)) + sys.exit(1) + + return 0 + + # + + def help_obj(self): + help = """\ + Usage: scons-time obj [OPTIONS] OBJECT FILE [...] + + -C DIR, --chdir=DIR Change to DIR before looking for files + -f FILE, --file=FILE Read configuration from specified FILE + --fmt=FORMAT, --format=FORMAT Print data in specified FORMAT + -h, --help Print this help and exit + -p STRING, --prefix=STRING Use STRING as log file/profile prefix + --stage=STAGE Plot memory at the specified stage: + pre-read, post-read, pre-build, + post-build (default: post-build) + -t NUMBER, --tail=NUMBER Only report the last NUMBER files + --title=TITLE Specify the output plot TITLE + """ + sys.stdout.write(self.outdent(help)) + sys.stdout.flush() + + def do_obj(self, argv): + + format = 'ascii' + logfile_path = lambda x: x + stage = self.default_stage + tail = None + + short_opts = '?C:f:hp:t:' + + long_opts = [ + 'chdir=', + 'file=', + 'fmt=', + 'format=', + 'help', + 'prefix=', + 'stage=', + 'tail=', + 'title=', + ] + + opts, args = getopt.getopt(argv[1:], short_opts, long_opts) + + for o, a in opts: + if o in ('-C', '--chdir'): + self.chdir = a + elif o in ('-f', '--file'): + self.config_file = a + elif o in ('--fmt', '--format'): + format = a + elif o in ('-?', '-h', '--help'): + self.do_help(['help', 'obj']) + sys.exit(0) + elif o in ('-p', '--prefix'): + self.prefix = a + elif o in ('--stage',): + if not a in self.stages: + sys.stderr.write('%s: obj: Unrecognized stage "%s".\n' % (self.name, a)) + sys.stderr.write('%s Type "%s help obj" for help.\n' % (self.name_spaces, self.name)) + sys.exit(1) + stage = a + elif o in ('-t', '--tail'): + tail = int(a) + elif o in ('--title',): + self.title = a + + if not args: + sys.stderr.write('%s: obj: Must specify an object name.\n' % self.name) + sys.stderr.write('%s Type "%s help obj" for help.\n' % (self.name_spaces, self.name)) + sys.exit(1) + + object_name = args.pop(0) + + if self.config_file: + with open(self.config_file, 'r') as f: + config = f.read() + HACK_for_exec(config, self.__dict__) + + if self.chdir: + os.chdir(self.chdir) + logfile_path = lambda x: os.path.join(self.chdir, x) + + if not args: + + pattern = '%s*.log' % self.prefix + args = self.args_to_files([pattern], tail) + + if not args: + if self.chdir: + directory = self.chdir + else: + directory = os.getcwd() + + sys.stderr.write('%s: obj: No arguments specified.\n' % self.name) + sys.stderr.write('%s No %s*.log files found in "%s".\n' % (self.name_spaces, self.prefix, directory)) + sys.stderr.write('%s Type "%s help obj" for help.\n' % (self.name_spaces, self.name)) + sys.exit(1) + + else: + + args = self.args_to_files(args, tail) + + cwd_ = os.getcwd() + os.sep + + if format == 'ascii': + + self.ascii_table(args, tuple(self.stages), self.get_object_counts, logfile_path, object_name) + + elif format == 'gnuplot': + + stage_index = 0 + for s in self.stages: + if stage == s: + break + stage_index = stage_index + 1 + + results = self.collect_results(args, self.get_object_counts, + object_name, stage_index) + + self.gnuplot_results(results) + + else: + + sys.stderr.write('%s: obj: Unknown format "%s".\n' % (self.name, format)) + sys.exit(1) + + return 0 + + # + + def help_run(self): + help = """\ + Usage: scons-time run [OPTIONS] [FILE ...] + + --aegis=PROJECT Use SCons from the Aegis PROJECT + --chdir=DIR Name of unpacked directory for chdir + -f FILE, --file=FILE Read configuration from specified FILE + -h, --help Print this help and exit + -n, --no-exec No execute, just print command lines + --number=NUMBER Put output in files for run NUMBER + --outdir=OUTDIR Put output files in OUTDIR + -p STRING, --prefix=STRING Use STRING as log file/profile prefix + --python=PYTHON Time using the specified PYTHON + -q, --quiet Don't print command lines + --scons=SCONS Time using the specified SCONS + --svn=URL, --subversion=URL Use SCons from Subversion URL + -v, --verbose Display output of commands + """ + sys.stdout.write(self.outdent(help)) + sys.stdout.flush() + + def do_run(self, argv): + """ + """ + run_number_list = [None] + + short_opts = '?f:hnp:qs:v' + + long_opts = [ + 'aegis=', + 'file=', + 'help', + 'no-exec', + 'number=', + 'outdir=', + 'prefix=', + 'python=', + 'quiet', + 'scons=', + 'svn=', + 'subdir=', + 'subversion=', + 'verbose', + ] + + opts, args = getopt.getopt(argv[1:], short_opts, long_opts) + + for o, a in opts: + if o in ('--aegis',): + self.aegis_project = a + elif o in ('-f', '--file'): + self.config_file = a + elif o in ('-?', '-h', '--help'): + self.do_help(['help', 'run']) + sys.exit(0) + elif o in ('-n', '--no-exec'): + self.execute = self._do_not_execute + elif o in ('--number',): + run_number_list = self.split_run_numbers(a) + elif o in ('--outdir',): + self.outdir = a + elif o in ('-p', '--prefix'): + self.prefix = a + elif o in ('--python',): + self.python = a + elif o in ('-q', '--quiet'): + self.display = self._do_not_display + elif o in ('-s', '--subdir'): + self.subdir = a + elif o in ('--scons',): + self.scons = a + elif o in ('--svn', '--subversion'): + self.subversion_url = a + elif o in ('-v', '--verbose'): + self.redirect = tee_to_file + self.verbose = True + self.svn_co_flag = '' + + if not args and not self.config_file: + sys.stderr.write('%s: run: No arguments or -f config file specified.\n' % self.name) + sys.stderr.write('%s Type "%s help run" for help.\n' % (self.name_spaces, self.name)) + sys.exit(1) + + if self.config_file: + with open(self.config_file, 'r') as f: + config = f.read() + exec(config, self.__dict__) + + if args: + self.archive_list = args + + archive_file_name = os.path.split(self.archive_list[0])[1] + + if not self.subdir: + self.subdir = self.archive_splitext(archive_file_name)[0] + + if not self.prefix: + self.prefix = self.archive_splitext(archive_file_name)[0] + + prepare = None + if self.subversion_url: + prepare = self.prep_subversion_run + elif self.aegis_project: + prepare = self.prep_aegis_run + + for run_number in run_number_list: + self.individual_run(run_number, self.archive_list, prepare) + + def split_run_numbers(self, s): + result = [] + for n in s.split(','): + try: + x, y = n.split('-') + except ValueError: + result.append(int(n)) + else: + result.extend(list(range(int(x), int(y)+1))) + return result + + def scons_path(self, dir): + return os.path.join(dir, 'src', 'script', 'scons.py') + + def scons_lib_dir_path(self, dir): + return os.path.join(dir, 'src', 'engine') + + def prep_aegis_run(self, commands, removals): + self.aegis_tmpdir = make_temp_file(prefix = self.name + '-aegis-') + removals.append((shutil.rmtree, 'rm -rf %%s', self.aegis_tmpdir)) + + self.aegis_parent_project = os.path.splitext(self.aegis_project)[0] + self.scons = self.scons_path(self.aegis_tmpdir) + self.scons_lib_dir = self.scons_lib_dir_path(self.aegis_tmpdir) + + commands.extend([ + 'mkdir %(aegis_tmpdir)s', + (lambda: os.chdir(self.aegis_tmpdir), 'cd %(aegis_tmpdir)s'), + '%(aegis)s -cp -ind -p %(aegis_parent_project)s .', + '%(aegis)s -cp -ind -p %(aegis_project)s -delta %(run_number)s .', + ]) + + def prep_subversion_run(self, commands, removals): + self.svn_tmpdir = make_temp_file(prefix = self.name + '-svn-') + removals.append((shutil.rmtree, 'rm -rf %%s', self.svn_tmpdir)) + + self.scons = self.scons_path(self.svn_tmpdir) + self.scons_lib_dir = self.scons_lib_dir_path(self.svn_tmpdir) + + commands.extend([ + 'mkdir %(svn_tmpdir)s', + '%(svn)s co %(svn_co_flag)s -r %(run_number)s %(subversion_url)s %(svn_tmpdir)s', + ]) + + def individual_run(self, run_number, archive_list, prepare=None): + """ + Performs an individual run of the default SCons invocations. + """ + + commands = [] + removals = [] + + if prepare: + prepare(commands, removals) + + save_scons = self.scons + save_scons_wrapper = self.scons_wrapper + save_scons_lib_dir = self.scons_lib_dir + + if self.outdir is None: + self.outdir = self.orig_cwd + elif not os.path.isabs(self.outdir): + self.outdir = os.path.join(self.orig_cwd, self.outdir) + + if self.scons is None: + self.scons = self.scons_path(self.orig_cwd) + + if self.scons_lib_dir is None: + self.scons_lib_dir = self.scons_lib_dir_path(self.orig_cwd) + + if self.scons_wrapper is None: + self.scons_wrapper = self.scons + + if not run_number: + run_number = self.find_next_run_number(self.outdir, self.prefix) + + self.run_number = str(run_number) + + self.prefix_run = self.prefix + '-%03d' % run_number + + if self.targets0 is None: + self.targets0 = self.startup_targets + if self.targets1 is None: + self.targets1 = self.targets + if self.targets2 is None: + self.targets2 = self.targets + + self.tmpdir = make_temp_file(prefix = self.name + '-') + + commands.extend([ + 'mkdir %(tmpdir)s', + + (os.chdir, 'cd %%s', self.tmpdir), + ]) + + for archive in archive_list: + if not os.path.isabs(archive): + archive = os.path.join(self.orig_cwd, archive) + if os.path.isdir(archive): + dest = os.path.split(archive)[1] + commands.append((shutil.copytree, 'cp -r %%s %%s', archive, dest)) + else: + suffix = self.archive_splitext(archive)[1] + unpack_command = self.unpack_map.get(suffix) + if not unpack_command: + dest = os.path.split(archive)[1] + commands.append((shutil.copyfile, 'cp %%s %%s', archive, dest)) + else: + commands.append(unpack_command + (archive,)) + + commands.extend([ + (os.chdir, 'cd %%s', self.subdir), + ]) + + commands.extend(self.initial_commands) + + commands.extend([ + (lambda: read_tree('.'), + 'find * -type f | xargs cat > /dev/null'), + + (self.set_env, 'export %%s=%%s', + 'SCONS_LIB_DIR', self.scons_lib_dir), + + '%(python)s %(scons_wrapper)s --version', + ]) + + index = 0 + for run_command in self.run_commands: + setattr(self, 'prof%d' % index, self.profile_name(index)) + c = ( + self.log_execute, + self.log_display, + run_command, + self.logfile_name(index), + ) + commands.append(c) + index = index + 1 + + commands.extend([ + (os.chdir, 'cd %%s', self.orig_cwd), + ]) + + if not os.environ.get('PRESERVE'): + commands.extend(removals) + + commands.append((shutil.rmtree, 'rm -rf %%s', self.tmpdir)) + + self.run_command_list(commands, self.__dict__) + + self.scons = save_scons + self.scons_lib_dir = save_scons_lib_dir + self.scons_wrapper = save_scons_wrapper + + # + + def help_time(self): + help = """\ + Usage: scons-time time [OPTIONS] FILE [...] + + -C DIR, --chdir=DIR Change to DIR before looking for files + -f FILE, --file=FILE Read configuration from specified FILE + --fmt=FORMAT, --format=FORMAT Print data in specified FORMAT + -h, --help Print this help and exit + -p STRING, --prefix=STRING Use STRING as log file/profile prefix + -t NUMBER, --tail=NUMBER Only report the last NUMBER files + --which=TIMER Plot timings for TIMER: total, + SConscripts, SCons, commands. + """ + sys.stdout.write(self.outdent(help)) + sys.stdout.flush() + + def do_time(self, argv): + + format = 'ascii' + logfile_path = lambda x: x + tail = None + which = 'total' + + short_opts = '?C:f:hp:t:' + + long_opts = [ + 'chdir=', + 'file=', + 'fmt=', + 'format=', + 'help', + 'prefix=', + 'tail=', + 'title=', + 'which=', + ] + + opts, args = getopt.getopt(argv[1:], short_opts, long_opts) + + for o, a in opts: + if o in ('-C', '--chdir'): + self.chdir = a + elif o in ('-f', '--file'): + self.config_file = a + elif o in ('--fmt', '--format'): + format = a + elif o in ('-?', '-h', '--help'): + self.do_help(['help', 'time']) + sys.exit(0) + elif o in ('-p', '--prefix'): + self.prefix = a + elif o in ('-t', '--tail'): + tail = int(a) + elif o in ('--title',): + self.title = a + elif o in ('--which',): + if not a in list(self.time_strings.keys()): + sys.stderr.write('%s: time: Unrecognized timer "%s".\n' % (self.name, a)) + sys.stderr.write('%s Type "%s help time" for help.\n' % (self.name_spaces, self.name)) + sys.exit(1) + which = a + + if self.config_file: + HACK_for_exec(open(self.config_file, 'r').read(), self.__dict__) + + if self.chdir: + os.chdir(self.chdir) + logfile_path = lambda x: os.path.join(self.chdir, x) + + if not args: + + pattern = '%s*.log' % self.prefix + args = self.args_to_files([pattern], tail) + + if not args: + if self.chdir: + directory = self.chdir + else: + directory = os.getcwd() + + sys.stderr.write('%s: time: No arguments specified.\n' % self.name) + sys.stderr.write('%s No %s*.log files found in "%s".\n' % (self.name_spaces, self.prefix, directory)) + sys.stderr.write('%s Type "%s help time" for help.\n' % (self.name_spaces, self.name)) + sys.exit(1) + + else: + + args = self.args_to_files(args, tail) + + cwd_ = os.getcwd() + os.sep + + if format == 'ascii': + + columns = ("Total", "SConscripts", "SCons", "commands") + self.ascii_table(args, columns, self.get_debug_times, logfile_path) + + elif format == 'gnuplot': + + results = self.collect_results(args, self.get_debug_times, + self.time_strings[which]) + + self.gnuplot_results(results, fmt='%s %.6f') + + else: + + sys.stderr.write('%s: time: Unknown format "%s".\n' % (self.name, format)) + sys.exit(1) + +if __name__ == '__main__': + opts, args = getopt.getopt(sys.argv[1:], 'h?V', ['help', 'version']) + + ST = SConsTimer() + + for o, a in opts: + if o in ('-?', '-h', '--help'): + ST.do_help(['help']) + sys.exit(0) + elif o in ('-V', '--version'): + sys.stdout.write('scons-time version\n') + sys.exit(0) + + if not args: + sys.stderr.write('Type "%s help" for usage.\n' % ST.name) + sys.exit(1) + + ST.execute_subcommand(args) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/scons.py b/tools/scons/scons.py new file mode 100755 index 0000000000..c0fe872e70 --- /dev/null +++ b/tools/scons/scons.py @@ -0,0 +1,210 @@ +#! /usr/bin/env python +# +# SCons - a Software Constructor +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +from __future__ import print_function + +__revision__ = "src/script/scons.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +__version__ = "3.0.5" + +__build__ = "a56bbd8c09fb219ab8a9673330ffcd55279219d0" + +__buildsys__ = "kufra" + +__date__ = "2019-03-26 23:16:31" + +__developer__ = "bdeegan" + +# This is the entry point to the SCons program. +# The only job of this script is to work out where the guts of the program +# could be and import them, where the real work begins. +# SCons can be invoked several different ways +# - from an installed location +# - from a "local install" copy +# - from a source tree, which has a different dir struture than the other two +# Try to account for all those possibilities. + +import os +import sys + +############################################################################## +# BEGIN STANDARD SCons SCRIPT HEADER +# +# This is the cut-and-paste logic so that a self-contained script can +# interoperate correctly with different SCons versions and installation +# locations for the engine. If you modify anything in this section, you +# should also change other scripts that use this same header. +############################################################################## + +# compatibility check +if (3,0,0) < sys.version_info < (3,5,0) or sys.version_info < (2,7,0): + msg = "scons: *** SCons version %s does not run under Python version %s.\n\ +Python 2.7 or >= 3.5 is required.\n" + sys.stderr.write(msg % (__version__, sys.version.split()[0])) + sys.exit(1) + +# Strip the script directory from sys.path so on case-insensitive +# (WIN32) systems Python doesn't think that the "scons" script is the +# "SCons" package. +script_dir = os.path.dirname(os.path.realpath(__file__)) +script_path = os.path.realpath(os.path.dirname(__file__)) +if script_path in sys.path: + sys.path.remove(script_path) + +libs = [] + +if "SCONS_LIB_DIR" in os.environ: + libs.append(os.environ["SCONS_LIB_DIR"]) + +# running from source takes 2nd priority (since 2.3.2), following SCONS_LIB_DIR +source_path = os.path.join(script_path, os.pardir, 'engine') +if os.path.isdir(source_path): + libs.append(source_path) + +# add local-install locations +local_version = 'scons-local-' + __version__ +local = 'scons-local' +if script_dir: + local_version = os.path.join(script_dir, local_version) + local = os.path.join(script_dir, local) +if os.path.isdir(local_version): + libs.append(os.path.abspath(local_version)) +if os.path.isdir(local): + libs.append(os.path.abspath(local)) + +scons_version = 'scons-%s' % __version__ + +# preferred order of scons lookup paths +prefs = [] + +# if we can find package information, use it +try: + import pkg_resources +except ImportError: + pass +else: + try: + d = pkg_resources.get_distribution('scons') + except pkg_resources.DistributionNotFound: + pass + else: + prefs.append(d.location) + +if sys.platform == 'win32': + # Use only sys.prefix on Windows + prefs.append(sys.prefix) + prefs.append(os.path.join(sys.prefix, 'Lib', 'site-packages')) +else: + # On other (POSIX) platforms, things are more complicated due to + # the variety of path names and library locations. + # Build up some possibilities, then transform them into candidates + temp = [] + if script_dir == 'bin': + # script_dir is `pwd`/bin; + # check `pwd`/lib/scons*. + temp.append(os.getcwd()) + else: + if script_dir == '.' or script_dir == '': + script_dir = os.getcwd() + head, tail = os.path.split(script_dir) + if tail == "bin": + # script_dir is /foo/bin; + # check /foo/lib/scons*. + temp.append(head) + + head, tail = os.path.split(sys.prefix) + if tail == "usr": + # sys.prefix is /foo/usr; + # check /foo/usr/lib/scons* first, + # then /foo/usr/local/lib/scons*. + temp.append(sys.prefix) + temp.append(os.path.join(sys.prefix, "local")) + elif tail == "local": + h, t = os.path.split(head) + if t == "usr": + # sys.prefix is /foo/usr/local; + # check /foo/usr/local/lib/scons* first, + # then /foo/usr/lib/scons*. + temp.append(sys.prefix) + temp.append(head) + else: + # sys.prefix is /foo/local; + # check only /foo/local/lib/scons*. + temp.append(sys.prefix) + else: + # sys.prefix is /foo (ends in neither /usr or /local); + # check only /foo/lib/scons*. + temp.append(sys.prefix) + + # suffix these to add to our original prefs: + prefs.extend([os.path.join(x, 'lib') for x in temp]) + prefs.extend([os.path.join(x, 'lib', 'python' + sys.version[:3], + 'site-packages') for x in temp]) + + + # Add the parent directory of the current python's library to the + # preferences. This picks up differences between, e.g., lib and lib64, + # and finds the base location in case of a non-copying virtualenv. + try: + libpath = os.__file__ + except AttributeError: + pass + else: + # Split /usr/libfoo/python*/os.py to /usr/libfoo/python*. + libpath, tail = os.path.split(libpath) + # Split /usr/libfoo/python* to /usr/libfoo + libpath, tail = os.path.split(libpath) + # Check /usr/libfoo/scons*. + prefs.append(libpath) + +# Look first for 'scons-__version__' in all of our preference libs, +# then for 'scons'. Skip paths that do not exist. +libs.extend([os.path.join(x, scons_version) for x in prefs if os.path.isdir(x)]) +libs.extend([os.path.join(x, 'scons') for x in prefs if os.path.isdir(x)]) + +sys.path = libs + sys.path + +############################################################################## +# END STANDARD SCons SCRIPT HEADER +############################################################################## + +if __name__ == "__main__": + try: + import SCons.Script + except ImportError: + sys.stderr.write("SCons import failed. Unable to find engine files in:\n") + for path in libs: + sys.stderr.write(" {}\n".format(path)) + raise + + # this does all the work, and calls sys.exit + # with the proper exit status when done. + SCons.Script.main() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/scons/sconsign.py b/tools/scons/sconsign.py new file mode 100755 index 0000000000..3b1e52dee9 --- /dev/null +++ b/tools/scons/sconsign.py @@ -0,0 +1,642 @@ +#! /usr/bin/env python +# +# SCons - a Software Constructor +# +# Copyright (c) 2001 - 2019 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +from __future__ import print_function + +__revision__ = "src/script/sconsign.py a56bbd8c09fb219ab8a9673330ffcd55279219d0 2019-03-26 23:16:31 bdeegan" + +__version__ = "3.0.5" + +__build__ = "a56bbd8c09fb219ab8a9673330ffcd55279219d0" + +__buildsys__ = "kufra" + +__date__ = "2019-03-26 23:16:31" + +__developer__ = "bdeegan" + +import os +import sys + +############################################################################## +# BEGIN STANDARD SCons SCRIPT HEADER +# +# This is the cut-and-paste logic so that a self-contained script can +# interoperate correctly with different SCons versions and installation +# locations for the engine. If you modify anything in this section, you +# should also change other scripts that use this same header. +############################################################################## + +# compatibility check +if (3,0,0) < sys.version_info < (3,5,0) or sys.version_info < (2,7,0): + msg = "scons: *** SCons version %s does not run under Python version %s.\n\ +Python 2.7 or >= 3.5 is required.\n" + sys.stderr.write(msg % (__version__, sys.version.split()[0])) + sys.exit(1) + +# Strip the script directory from sys.path so on case-insensitive +# (WIN32) systems Python doesn't think that the "scons" script is the +# "SCons" package. +script_dir = os.path.dirname(os.path.realpath(__file__)) +script_path = os.path.realpath(os.path.dirname(__file__)) +if script_path in sys.path: + sys.path.remove(script_path) + +libs = [] + +if "SCONS_LIB_DIR" in os.environ: + libs.append(os.environ["SCONS_LIB_DIR"]) + +# running from source takes 2nd priority (since 2.3.2), following SCONS_LIB_DIR +source_path = os.path.join(script_path, os.pardir, 'engine') +if os.path.isdir(source_path): + libs.append(source_path) + +# add local-install locations +local_version = 'scons-local-' + __version__ +local = 'scons-local' +if script_dir: + local_version = os.path.join(script_dir, local_version) + local = os.path.join(script_dir, local) +if os.path.isdir(local_version): + libs.append(os.path.abspath(local_version)) +if os.path.isdir(local): + libs.append(os.path.abspath(local)) + +scons_version = 'scons-%s' % __version__ + +# preferred order of scons lookup paths +prefs = [] + +# if we can find package information, use it +try: + import pkg_resources +except ImportError: + pass +else: + try: + d = pkg_resources.get_distribution('scons') + except pkg_resources.DistributionNotFound: + pass + else: + prefs.append(d.location) + +if sys.platform == 'win32': + # Use only sys.prefix on Windows + prefs.append(sys.prefix) + prefs.append(os.path.join(sys.prefix, 'Lib', 'site-packages')) +else: + # On other (POSIX) platforms, things are more complicated due to + # the variety of path names and library locations. + # Build up some possibilities, then transform them into candidates + temp = [] + if script_dir == 'bin': + # script_dir is `pwd`/bin; + # check `pwd`/lib/scons*. + temp.append(os.getcwd()) + else: + if script_dir == '.' or script_dir == '': + script_dir = os.getcwd() + head, tail = os.path.split(script_dir) + if tail == "bin": + # script_dir is /foo/bin; + # check /foo/lib/scons*. + temp.append(head) + + head, tail = os.path.split(sys.prefix) + if tail == "usr": + # sys.prefix is /foo/usr; + # check /foo/usr/lib/scons* first, + # then /foo/usr/local/lib/scons*. + temp.append(sys.prefix) + temp.append(os.path.join(sys.prefix, "local")) + elif tail == "local": + h, t = os.path.split(head) + if t == "usr": + # sys.prefix is /foo/usr/local; + # check /foo/usr/local/lib/scons* first, + # then /foo/usr/lib/scons*. + temp.append(sys.prefix) + temp.append(head) + else: + # sys.prefix is /foo/local; + # check only /foo/local/lib/scons*. + temp.append(sys.prefix) + else: + # sys.prefix is /foo (ends in neither /usr or /local); + # check only /foo/lib/scons*. + temp.append(sys.prefix) + + # suffix these to add to our original prefs: + prefs.extend([os.path.join(x, 'lib') for x in temp]) + prefs.extend([os.path.join(x, 'lib', 'python' + sys.version[:3], + 'site-packages') for x in temp]) + + + # Add the parent directory of the current python's library to the + # preferences. This picks up differences between, e.g., lib and lib64, + # and finds the base location in case of a non-copying virtualenv. + try: + libpath = os.__file__ + except AttributeError: + pass + else: + # Split /usr/libfoo/python*/os.py to /usr/libfoo/python*. + libpath, _ = os.path.split(libpath) + # Split /usr/libfoo/python* to /usr/libfoo + libpath, tail = os.path.split(libpath) + # Check /usr/libfoo/scons*. + prefs.append(libpath) + +# Look first for 'scons-__version__' in all of our preference libs, +# then for 'scons'. Skip paths that do not exist. +libs.extend([os.path.join(x, scons_version) for x in prefs if os.path.isdir(x)]) +libs.extend([os.path.join(x, 'scons') for x in prefs if os.path.isdir(x)]) + +sys.path = libs + sys.path + +############################################################################## +# END STANDARD SCons SCRIPT HEADER +############################################################################## + +import SCons.compat + +try: + import whichdb + whichdb = whichdb.whichdb +except ImportError as e: + from dbm import whichdb + +import time +import pickle +import imp + +import SCons.SConsign + + +def my_whichdb(filename): + if filename[-7:] == ".dblite": + return "SCons.dblite" + try: + f = open(filename + ".dblite", "rb") + f.close() + return "SCons.dblite" + except IOError: + pass + return _orig_whichdb(filename) + + +# Should work on python2 +_orig_whichdb = whichdb +whichdb = my_whichdb + +# was changed for python3 +#_orig_whichdb = whichdb.whichdb +#dbm.whichdb = my_whichdb + +def my_import(mname): + if '.' in mname: + i = mname.rfind('.') + parent = my_import(mname[:i]) + fp, pathname, description = imp.find_module(mname[i+1:], + parent.__path__) + else: + fp, pathname, description = imp.find_module(mname) + return imp.load_module(mname, fp, pathname, description) + + +class Flagger(object): + default_value = 1 + + def __setitem__(self, item, value): + self.__dict__[item] = value + self.default_value = 0 + + def __getitem__(self, item): + return self.__dict__.get(item, self.default_value) + + +Do_Call = None +Print_Directories = [] +Print_Entries = [] +Print_Flags = Flagger() +Verbose = 0 +Readable = 0 +Warns = 0 + + + +def default_mapper(entry, name): + ''' + Stringify an entry that doesn't have an explicit mapping. + + Args: + entry: entry + name: field name + + Returns: str + + ''' + try: + val = eval("entry." + name) + except: + val = None + if sys.version_info.major >= 3 and isinstance(val, bytes): + # This is a dirty hack for py 2/3 compatibility. csig is a bytes object + # in Python3 while Python2 bytes are str. Hence, we decode the csig to a + # Python3 string + val = val.decode() + return str(val) + + +def map_action(entry, _): + ''' + Stringify an action entry and signature. + + Args: + entry: action entry + second argument is not used + + Returns: str + + ''' + try: + bact = entry.bact + bactsig = entry.bactsig + except AttributeError: + return None + return '%s [%s]' % (bactsig, bact) + +def map_timestamp(entry, _): + ''' + Stringify a timestamp entry. + + Args: + entry: timestamp entry + second argument is not used + + Returns: str + + ''' + try: + timestamp = entry.timestamp + except AttributeError: + timestamp = None + if Readable and timestamp: + return "'" + time.ctime(timestamp) + "'" + else: + return str(timestamp) + +def map_bkids(entry, _): + ''' + Stringify an implicit entry. + + Args: + entry: + second argument is not used + + Returns: str + + ''' + try: + bkids = entry.bsources + entry.bdepends + entry.bimplicit + bkidsigs = entry.bsourcesigs + entry.bdependsigs + entry.bimplicitsigs + except AttributeError: + return None + + if len(bkids) != len(bkidsigs): + global Warns + Warns += 1 + # add warning to result rather than direct print so it will line up + msg = "Warning: missing information, {} ids but {} sigs" + result = [msg.format(len(bkids), len(bkidsigs))] + else: + result = [] + result += [nodeinfo_string(bkid, bkidsig, " ") + for bkid, bkidsig in zip(bkids, bkidsigs)] + if not result: + return None + return "\n ".join(result) + + +map_field = { + 'action' : map_action, + 'timestamp' : map_timestamp, + 'bkids' : map_bkids, +} + +map_name = { + 'implicit' : 'bkids', +} + + +def field(name, entry, verbose=Verbose): + if not Print_Flags[name]: + return None + fieldname = map_name.get(name, name) + mapper = map_field.get(fieldname, default_mapper) + val = mapper(entry, name) + if verbose: + val = name + ": " + val + return val + + +def nodeinfo_raw(name, ninfo, prefix=""): + # This just formats the dictionary, which we would normally use str() + # to do, except that we want the keys sorted for deterministic output. + d = ninfo.__getstate__() + try: + keys = ninfo.field_list + ['_version_id'] + except AttributeError: + keys = sorted(d.keys()) + l = [] + for k in keys: + l.append('%s: %s' % (repr(k), repr(d.get(k)))) + if '\n' in name: + name = repr(name) + return name + ': {' + ', '.join(l) + '}' + + +def nodeinfo_cooked(name, ninfo, prefix=""): + try: + field_list = ninfo.field_list + except AttributeError: + field_list = [] + if '\n' in name: + name = repr(name) + outlist = [name + ':'] + [ + f for f in [field(x, ninfo, Verbose) for x in field_list] if f + ] + if Verbose: + sep = '\n ' + prefix + else: + sep = ' ' + return sep.join(outlist) + + +nodeinfo_string = nodeinfo_cooked + + +def printfield(name, entry, prefix=""): + outlist = field("implicit", entry, 0) + if outlist: + if Verbose: + print(" implicit:") + print(" " + outlist) + outact = field("action", entry, 0) + if outact: + if Verbose: + print(" action: " + outact) + else: + print(" " + outact) + + +def printentries(entries, location): + if Print_Entries: + for name in Print_Entries: + try: + entry = entries[name] + except KeyError: + err = "sconsign: no entry `%s' in `%s'\n" % (name, location) + sys.stderr.write(err) + else: + try: + ninfo = entry.ninfo + except AttributeError: + print(name + ":") + else: + print(nodeinfo_string(name, entry.ninfo)) + printfield(name, entry.binfo) + else: + for name in sorted(entries.keys()): + entry = entries[name] + try: + ninfo = entry.ninfo + except AttributeError: + print(name + ":") + else: + print(nodeinfo_string(name, entry.ninfo)) + printfield(name, entry.binfo) + + +class Do_SConsignDB(object): + def __init__(self, dbm_name, dbm): + self.dbm_name = dbm_name + self.dbm = dbm + + def __call__(self, fname): + # The *dbm modules stick their own file suffixes on the names + # that are passed in. This is causes us to jump through some + # hoops here to be able to allow the user + try: + # Try opening the specified file name. Example: + # SPECIFIED OPENED BY self.dbm.open() + # --------- ------------------------- + # .sconsign => .sconsign.dblite + # .sconsign.dblite => .sconsign.dblite.dblite + db = self.dbm.open(fname, "r") + except (IOError, OSError) as e: + print_e = e + try: + # That didn't work, so try opening the base name, + # so that if the actually passed in 'sconsign.dblite' + # (for example), the dbm module will put the suffix back + # on for us and open it anyway. + db = self.dbm.open(os.path.splitext(fname)[0], "r") + except (IOError, OSError): + # That didn't work either. See if the file name + # they specified just exists (independent of the dbm + # suffix-mangling). + try: + open(fname, "r") + except (IOError, OSError) as e: + # Nope, that file doesn't even exist, so report that + # fact back. + print_e = e + sys.stderr.write("sconsign: %s\n" % print_e) + return + except KeyboardInterrupt: + raise + except pickle.UnpicklingError: + sys.stderr.write("sconsign: ignoring invalid `%s' file `%s'\n" + % (self.dbm_name, fname)) + return + except Exception as e: + sys.stderr.write("sconsign: ignoring invalid `%s' file `%s': %s\n" + % (self.dbm_name, fname, e)) + return + + if Print_Directories: + for dir in Print_Directories: + try: + val = db[dir] + except KeyError: + err = "sconsign: no dir `%s' in `%s'\n" % (dir, args[0]) + sys.stderr.write(err) + else: + self.printentries(dir, val) + else: + for dir in sorted(db.keys()): + self.printentries(dir, db[dir]) + + @staticmethod + def printentries(dir, val): + try: + print('=== ' + dir + ':') + except TypeError: + print('=== ' + dir.decode() + ':') + printentries(pickle.loads(val), dir) + + +def Do_SConsignDir(name): + try: + fp = open(name, 'rb') + except (IOError, OSError) as e: + sys.stderr.write("sconsign: %s\n" % e) + return + try: + sconsign = SCons.SConsign.Dir(fp) + except KeyboardInterrupt: + raise + except pickle.UnpicklingError: + err = "sconsign: ignoring invalid .sconsign file `%s'\n" % (name) + sys.stderr.write(err) + return + except Exception as e: + err = "sconsign: ignoring invalid .sconsign file `%s': %s\n" % (name, e) + sys.stderr.write(err) + return + printentries(sconsign.entries, args[0]) + + +############################################################################## + +import getopt + +helpstr = """\ +Usage: sconsign [OPTIONS] FILE [...] +Options: + -a, --act, --action Print build action information. + -c, --csig Print content signature information. + -d DIR, --dir=DIR Print only info about DIR. + -e ENTRY, --entry=ENTRY Print only info about ENTRY. + -f FORMAT, --format=FORMAT FILE is in the specified FORMAT. + -h, --help Print this message and exit. + -i, --implicit Print implicit dependency information. + -r, --readable Print timestamps in human-readable form. + --raw Print raw Python object representations. + -s, --size Print file sizes. + -t, --timestamp Print timestamp information. + -v, --verbose Verbose, describe each field. +""" + +opts, args = getopt.getopt(sys.argv[1:], "acd:e:f:hirstv", + ['act', 'action', + 'csig', 'dir=', 'entry=', + 'format=', 'help', 'implicit', + 'raw', 'readable', + 'size', 'timestamp', 'verbose']) + + +for o, a in opts: + if o in ('-a', '--act', '--action'): + Print_Flags['action'] = 1 + elif o in ('-c', '--csig'): + Print_Flags['csig'] = 1 + elif o in ('-d', '--dir'): + Print_Directories.append(a) + elif o in ('-e', '--entry'): + Print_Entries.append(a) + elif o in ('-f', '--format'): + # Try to map the given DB format to a known module + # name, that we can then try to import... + Module_Map = {'dblite': 'SCons.dblite', 'sconsign': None} + dbm_name = Module_Map.get(a, a) + if dbm_name: + try: + if dbm_name != "SCons.dblite": + dbm = my_import(dbm_name) + else: + import SCons.dblite + + dbm = SCons.dblite + # Ensure that we don't ignore corrupt DB files, + # this was handled by calling my_import('SCons.dblite') + # again in earlier versions... + SCons.dblite.ignore_corrupt_dbfiles = 0 + except: + sys.stderr.write("sconsign: illegal file format `%s'\n" % a) + print(helpstr) + sys.exit(2) + Do_Call = Do_SConsignDB(a, dbm) + else: + Do_Call = Do_SConsignDir + elif o in ('-h', '--help'): + print(helpstr) + sys.exit(0) + elif o in ('-i', '--implicit'): + Print_Flags['implicit'] = 1 + elif o in ('--raw',): + nodeinfo_string = nodeinfo_raw + elif o in ('-r', '--readable'): + Readable = 1 + elif o in ('-s', '--size'): + Print_Flags['size'] = 1 + elif o in ('-t', '--timestamp'): + Print_Flags['timestamp'] = 1 + elif o in ('-v', '--verbose'): + Verbose = 1 + +if Do_Call: + for a in args: + Do_Call(a) +else: + for a in args: + dbm_name = whichdb(a) + if dbm_name: + Map_Module = {'SCons.dblite': 'dblite'} + if dbm_name != "SCons.dblite": + dbm = my_import(dbm_name) + else: + import SCons.dblite + + dbm = SCons.dblite + # Ensure that we don't ignore corrupt DB files, + # this was handled by calling my_import('SCons.dblite') + # again in earlier versions... + SCons.dblite.ignore_corrupt_dbfiles = 0 + Do_SConsignDB(Map_Module.get(dbm_name, dbm_name), dbm)(a) + else: + Do_SConsignDir(a) + + if Warns: + print("NOTE: there were %d warnings, please check output" % Warns) +sys.exit(0) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/tools/utils/__init__.py b/tools/utils/__init__.py new file mode 100755 index 0000000000..c0865d1883 --- /dev/null +++ b/tools/utils/__init__.py @@ -0,0 +1,15 @@ +# Copyright 2019 Autodesk, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from . import build_tools, color, compiler, elf, git, \ + path, regression_test, system, test_stats, testsuite, valgrind diff --git a/tools/utils/build_tools.py b/tools/utils/build_tools.py new file mode 100755 index 0000000000..1a6e8615aa --- /dev/null +++ b/tools/utils/build_tools.py @@ -0,0 +1,216 @@ +# vim: filetype=python +# Copyright 2019 Autodesk, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os + +## load our own python modules +from . import system + +from itertools import izip + +def process_return_code(retcode): + ''' + translates a process return code (as obtained by os.system or subprocess) into a status string + ''' + if retcode == 0: + status = 'OK' + else: + if system.is_windows: + if retcode < 0: + status = 'CRASHED' + else: + status = 'FAILED' + else: + # When a signal "N" is raised, the process can + # return with status "128 + N" or "-N" + if retcode > 128 or retcode < 0: + status = 'CRASHED' + else: + status = 'FAILED' + return status + +## Searches for file in the system path. Returns a list of directories containing file +def find_in_path(file): + path = os.environ['PATH'] + path = string.split(path, os.pathsep) + return filter(os.path.exists, map(lambda dir, file=file: os.path.join(dir, file), path)) + +## Returns a list of all files with an extension from the 'valid_extensions' list +def find_files_recursive(path, valid_extensions): + path = os.path.normpath(path) + list = [] + for root, dirs, files in os.walk(path): + if '.svn' in dirs: + dirs.remove('.svn') + for f in files: + if os.path.splitext(f)[1] in valid_extensions: + # Build the absolute path and then remove the root path, to get the relative path from root + file = os.path.join(root, f)[len(path) + 1:] + list += [file] + return list + +## Copy directories recursively, ignoring .svn dirs +## directory must not exist +def copy_dir_recursive(src, dest): + for f in os.listdir(src): + src_path = os.path.join(src, f) + dest_path = os.path.join(dest, f) + if os.path.isdir(src_path): + if f != '.svn': + if not os.path.exists(dest_path): + os.makedirs(dest_path) + #shutil.copystat(src_path, dest_path) + copy_dir_recursive(src_path, dest_path) + else: + shutil.copy2(src_path, dest_path) + +def get_arnold_version(arnold_include_dir, components = 4): + '''Obtain Arnold library version by parsing 'ai_version.h' + ''' + ARCH_VERSION='' + MAJOR_VERSION='' + MINOR_VERSION='' + FIX_VERSION='' + + ai_version_h = os.path.join(arnold_include_dir, 'ai_version.h') + f = open(ai_version_h, 'r') + + while True: + line = f.readline().lstrip(' \t') + if line == "": + # We have reached the end of file. + break + if line.startswith('#define'): + tokens = line.split() + if tokens[1] == 'AI_VERSION_ARCH_NUM': + ARCH_VERSION = tokens[2] + elif tokens[1] == 'AI_VERSION_MAJOR_NUM': + MAJOR_VERSION = tokens[2] + elif tokens[1] == 'AI_VERSION_MINOR_NUM': + MINOR_VERSION = tokens[2] + elif tokens[1] == 'AI_VERSION_FIX': + FIX_VERSION = tokens[2].strip('"') + f.close() + + if (components > 0): + version = ARCH_VERSION + if (components > 1): + version += '.' + MAJOR_VERSION + if (components > 2): + version += '.' + MINOR_VERSION + if (components > 3): + version += '.' + FIX_VERSION + + return version + +def get_usd_version(usd_include_dir, components=3): + VERSION = [''] * 3 + + pxr_h = os.path.join(usd_include_dir, 'pxr', 'pxr.h') + f = open(pxr_h, 'r') + + while True: + line = f.readline().lstrip(' \t') + if line == "": + # We have reached the end of file. + break + if line.startswith('#define'): + tokens = line.split() + if tokens[1] == 'PXR_MAJOR_VERSION': + VERSION[0] = tokens[2] + elif tokens[1] == 'PXR_MINOR_VERSION': + VERSION[1] = tokens[2] + elif tokens[1] == 'PXR_PATCH_VERSION': + VERSION[2] = tokens[2] + f.close() + + return '.'.join(VERSION[:components]) + +def convert_usd_version_to_int(usd_version): + sum = 0 + for v, m in izip(usd_version.split('.'), [10000, 100, 1]): + sum += int(v) * m + return sum + +def add_to_library_path(env, new_path): + if system.os == 'windows': + var_name = 'PATH' + elif system.os == 'darwin': + var_name = 'DYLD_LIBRARY_PATH' + else: + var_name = 'LD_LIBRARY_PATH' + + if env['ENV'].has_key(var_name): + env['ENV'][var_name] = '%s%s%s' % (new_path, os.pathsep, env['ENV'][var_name]) + else: + env['ENV'][var_name] = new_path + +def set_library_path(env): + if system.os == 'windows': + var_name = 'PATH' + elif system.os == 'darwin': + var_name = 'DYLD_LIBRARY_PATH' + else: + var_name = 'LD_LIBRARY_PATH' + + env['PREVIOUS_LIBRARY_PATH'] = '' + if os.environ.has_key(var_name): + env['PREVIOUS_LIBRARY_PATH'] = os.environ[var_name] + os.environ[var_name] = env['ENV'][var_name] + +def reset_library_path(env): + if env.has_key('PREVIOUS_LIBRARY_PATH'): + if system.os == 'windows': + var_name = 'PATH' + elif system.os == 'darwin': + var_name = 'DYLD_LIBRARY_PATH' + else: + var_name = 'LD_LIBRARY_PATH' + os.environ[var_name] = env['PREVIOUS_LIBRARY_PATH'] + +def add_to_program_path(env, new_path): + if env['ENV'].has_key('PATH'): + env['ENV']['PATH'] = '%s%s%s' % (new_path, os.pathsep, env['ENV']['PATH']) + else: + env['ENV']['PATH'] = new_path + +def set_program_path(env): + env['PREVIOUS_PROGRAM_PATH'] = '' + if os.environ.has_key('PATH'): + env['PREVIOUS_PROGRAM_PATH'] = os.environ['PATH'] + os.environ['PATH'] = env['ENV']['PATH'] + +def reset_program_path(env): + if env.has_key('PREVIOUS_PROGRAM_PATH'): + os.environ['PATH'] = env['PREVIOUS_PROGRAM_PATH'] + +def get_default_path(var, default): + if var in os.environ: + return os.environ[var] + else: + return default + +def get_escaped_path(path): + if system.os() == 'windows': + return path.replace("\\", "\\\\") + else: + return path + +def link_usd_libraries(env, libs): + lib_prefix = env['USD_LIB_PREFIX'] + usd_lib = env['USD_LIB'] + if env['USD_LIB_AS_SOURCE']: + return [], [os.path.join(usd_lib, '%s%s%s' % (lib_prefix, lib, system.LIB_EXTENSION)) for lib in libs] + else: + return ['%s%s' % (lib_prefix, lib) for lib in libs], [] diff --git a/tools/utils/color.py b/tools/utils/color.py new file mode 100755 index 0000000000..41a9647344 --- /dev/null +++ b/tools/utils/color.py @@ -0,0 +1,44 @@ +# vim: filetype=python +# Copyright 2019 Autodesk, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from .contrib import colorama +from . import system + +class _ANSI_Codes(object): + def __init__(self, codes): + for name in dir(codes): + if not name.startswith('_'): + setattr(self, name.lower(), '') + def init_attributes(self, codes): + for name in dir(codes): + if not name.startswith('_'): + setattr(self, name.lower(), getattr(codes, name)) + +fg = _ANSI_Codes(colorama.Fore) +bg = _ANSI_Codes(colorama.Back) +st = _ANSI_Codes(colorama.Style) + +def init(): + global fg, bg, st + colorama.init(convert=system.is_windows) + fg.init_attributes(colorama.Fore) + bg.init_attributes(colorama.Back) + st.init_attributes(colorama.Style) + +def fmt(s, fore=None, back=None, style=None): + tmp = s + if style: tmp = style + tmp + st.reset_all + if fore : tmp = fore + tmp + fg.reset + if back : tmp = back + tmp + bg.reset + return tmp diff --git a/tools/utils/compiler.py b/tools/utils/compiler.py new file mode 100755 index 0000000000..dbc100cfd7 --- /dev/null +++ b/tools/utils/compiler.py @@ -0,0 +1,638 @@ +# vim: filetype=python +# Copyright 2019 Autodesk, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from SCons.Script import * + +import os, shlex, subprocess, tempfile + +from . import system +from .version import Version + +allowed = { + 'darwin' : ('clang:4.0.0', 'gcc'), + 'linux' : ('clang:4.0.0', 'gcc', 'icc'), + 'windows': ('icc:17.0.2',), +}.get(system.os, None) + +def _dump_macros(env, bin): + ## Create a temporal c++ compilation unit + f = tempfile.NamedTemporaryFile(suffix='.cc', delete=False) + f.write('#include \n') + f.close() + ## Dump macro definitions + cmd = [bin, '-dM', '-E', '-x', 'c++', f.name] + _, lines = system.execute(cmd, env=env['ENV']) + ## Remove the temporal c++ compilation unit + os.remove(f.name) + return lines + +def get_defines(env, bin, m): + r = [None] * len(m) + for l in _dump_macros(env, bin): + ls = l.split() + for i in range(len(r)): + if ls[:2] == ['#define', m[i]]: r[i] = ls[2] + return r + +def detect_version(env, bin, m): + ''' + Detect version by parsing predefined macros + ''' + v = [None] * len(m) + for l in _dump_macros(env, bin): + ls = l.split() + for i in range(len(v)): + if ls[:2] == ['#define', m[i]] and v[i] == None: v[i] = int(ls[2]) + n = next((i for i in range(len(v)) if v[i] == None), len(v)) + return Version(v[:n]) + +def detect_gcc_version (env, bin): return detect_version(env, bin, ['__GNUC__','__GNUC_MINOR__' ,'__GNUC_PATCHLEVEL__' ]) +def detect_clang_version(env, bin): return detect_version(env, bin, ['__clang_major__','__clang_minor__','__clang_patchlevel__']) + +def validator(key, val, env): + ## Convert the tuple of strings with allowed compilers and versions ... + ## ('clang:3.4.0', 'icc:14.0.2', 'gcc') + ## ... into a proper dictionary ... + ## {'clang' : '3.4.0', 'icc' : '14.0.2', 'gcc' : None} + allowed_versions = {i[0] : i[1] if len(i) == 2 else None for i in (j.split(':') for j in allowed)} + ## Parse the compiler format string : + compiler = val.split(':') + ## Validate if it's an allowed compiler + if compiler[0] not in allowed_versions.keys(): + m = 'Invalid value for option {}: {}. Valid values are: {}' + raise SCons.Errors.UserError(m.format(key, val, allowed_versions.keys())) + ## Set valid compiler name and version. If the version was not specified + ## we will set the default version which we use in the official releases, + ## so the build will fail if it cannot be found. + env['_COMPILER'] = compiler[0] + env['_COMPILER_VERSION'] = len(compiler) == 2 and compiler[1] or allowed_versions[compiler[0]] + +def configure(env): + + # Get an alias dictionary for the Scons construction environment, so we can + # de-reference it with the '**' operator in some function calls. + env_dict = env.Dictionary() + + # Initialize a dictionary of compiler flags. Once every flag is collected in + # the following lists, we will pass this dict to the env.Append() function + # for appending them to the SCons construction environment 'env'. + compiler_flags = { + 'CPPDEFINES' : [], # C/C++ preprocessor directives + 'CCFLAGS' : [], # C compiler flags + 'CXXFLAGS' : [], # C++ compiler flags + 'LINKFLAGS' : [], # Linker flags + 'RPATH' : [], # Runtime paths + } + # Create shorter aliases for every entry in the previous dictionary, so we + # can write less verbose code. + CPPDEFS = compiler_flags['CPPDEFINES'] + CFLAGS = compiler_flags['CCFLAGS' ] + CXXFLAGS = compiler_flags['CXXFLAGS' ] + LDFLAGS = compiler_flags['LINKFLAGS' ] + RPATH = compiler_flags['RPATH' ] + + # Preconfigure some common characters used in the compilers flags for + # negating, prefixing, etc. + # For example, in Windows, flags are prefixed by "/" instead of "-" (Linux). + # "Q" prefix is also common in windows and flags are commonly negated with + # a trailing "-", whereas Linux/OSX uses "no-" for negating features. + flag_prefix = '/' if system.is_windows else '-' + flag_Q = 'Q' if system.is_windows else '' + flag_neg = '-' if system.is_windows else 'no-' + flag_sep = ':' if system.is_windows else '=' + def enable_in(mode): + # Return the corresponding charater for enabling a flag if env['MODE'] is + # 'mode'. Disable otherwise in the rest of modes. This makes sense only + # for compiler features that can be enabled/disabled with the same flag + return flag_neg if env['MODE'] not in [mode] else '' + + ## Detect compiler selected/installed versions ############################## + if env['_COMPILER'] == 'gcc': + env['CC'] = 'gcc' + env['CXX'] = 'g++' + env['COMPILER_VERSION_DETECTED'] = detect_gcc_version(env, env['CXX']) + elif env['_COMPILER'] == 'clang': + env.Tool('clang', version = env['_COMPILER_VERSION']) + elif env['_COMPILER'] == 'icc': + env.Tool('intelc', version = env['_COMPILER_VERSION']) + # If provided, use the following GCC toolchain to set up the environment + # for C/C++ compilations, otherwise ICC will use the system GCC. + gcc_toolchain = env.get('GCC_SUPPORT_ROOT') + if gcc_toolchain: + CFLAGS += ['cxxlib={}'.format(gcc_toolchain)] + LDFLAGS += ['cxxlib={}'.format(gcc_toolchain)] + + ## Inject compiler name and version with C/C++ preprocessor directives + compiler_prefix = env.get('COMPILER_PREFIX', '') + compiler_prefix += '-' if compiler_prefix else '' + compiler_name = env['_COMPILER'] + compiler_version = env['COMPILER_VERSION_DETECTED'] + CPPDEFS += [{'__AI_COMPILER__' : '\\"{0}{1}\\"'.format(compiler_prefix, compiler_name)}] + CPPDEFS += [{'__AI_COMPILER_MAJOR__' : compiler_version[0]}] + CPPDEFS += [{'__AI_COMPILER_MINOR__' : compiler_version[1]}] + CPPDEFS += [{'__AI_COMPILER_PATCH__' : compiler_version[2]}] + CPPDEFS += [{'__AI_COMPILER_{}__'.format(compiler_name.upper()) : \ + sum(a*b for a,b in zip(compiler_version[:3], [10000,100,1]))}] + + ## Conform to a given C++ language standard ################################# + if (compiler_name, env['STDCXX']) != ('icc', '98'): + CXXFLAGS += ['{0}std=c++{STDCXX}'.format(flag_Q, **env_dict)] + # NOTE (#4713): Full C++11 support in darwin requires using LLVM's libc++ + # standard library instead of GNU's libstdc++. + if system.is_darwin: + CXXFLAGS += ['stdlib=libc++'] + LDFLAGS += ['stdlib=libc++'] + # NOTE (#4986): In the GCC 5.1 release libstdc++ introduced a new library ABI + # that includes new implementations of std::string and std::list. The + # _GLIBCXX_USE_CXX11_ABI macro controls whether the declarations in the + # library headers use the old or new ABI. + if system.is_linux: + CPPDEFS += [{'_GLIBCXX_USE_CXX11_ABI' : 0}] + + ## Control warning and error diagnostics and verbosity ###################### + if env['WARN_LEVEL'] == 'none': + # Disables all warning messages + CFLAGS += ['w'] + else: + # NOTE (icc): On Windows, /Wall is equivalent to /W4. It enables + # diagnostics for all level 3 warnings plus informational warnings and + # remarks. However, on icc Linux/OSX, it displays all errors and some of + # the warnings that are typically reported by gcc option -Wall, so we + # have to might explicitely enable the remarks (-Wremarks) if wanted. + CFLAGS += ['Wall'] + # Enable also some extra warning flags that are not enabled by -Wall + CFLAGS += ['Wextra'] if not system.is_windows else [] + # Changes all warnings to errors if we want to be strict + if env['WARN_LEVEL'] == 'strict': + CFLAGS += ['Werror'] if not system.is_windows else ['WX'] + + # Disable selected diagnostics by compiler / platform + + if compiler_name in ['clang', 'gcc']: + # Disable selected warnings from -Wextra + CFLAGS += ['Wno-unused-parameter'] + CFLAGS += ['Wno-unused-local-typedef'] + + if compiler_name == 'gcc': + # Disable selected warnings from -Wextra + CFLAGS += ['Wno-unused-variable'] + CFLAGS += ['Wno-strict-aliasing'] + CFLAGS += ['Wno-format-zero-length'] + CFLAGS += ['Wno-unused-but-set-parameter'] # in gcc 4.6+ + CFLAGS += ['Wno-maybe-uninitialized'] # in gcc 4.7+ + + if compiler_name == 'clang': + # Some automatically generated .cpp files use the "register" keyword (flex + # and bison). Such "register" keyword is deprecated in C++11 (and it will + # be removed in C++17) so clang is currently generating a warning. + # We will disable that warning if clang >= 3.4 or apple-clang >= 5.1 + if (compiler_prefix == 'apple' and compiler_version >= Version('5.1')) or \ + (compiler_prefix != 'apple' and compiler_version >= Version('3.4')): + CXXFLAGS += ['Wno-deprecated-register'] + + if compiler_name == 'icc': + # Disables the following warnings: + warn_ids = [ + 111, # statement is unreachable (needed for parser generated code) + 181, # compatibility checks between variable type and printf mask + 280, # selector expression is constant + 367, # duplicate friend declaration (OpenVDB headers) + 504, # initial value of reference to non-const must be an lvalue (Boost headers) + 869, # parameter XXXX was never referenced + 1879, # unimplemented pragma ignored (TBB headers) + 2586, # decorated name length exceeded, name was truncated (OpenVDB headers) + 2960, # class allocated with new might not be aligned (we should review this) + 3280, # declaration hides existing member or variable (we should review this) + 3346, # (remark) Dynamic exception specifications are deprecated (OpenEXR headers) + 11074, # (remark) Inlining inhibited by limit max-size|max-total-size + 11075, # (remark) To get full report use -Qopt-report:4 -Qopt-report-phase ipo (Windows) + 11076, # (remark) To get full report use -qopt-report=4 -qopt-report-phase ipo (Linux) + ] + CFLAGS += ['{}diag-disable{}{}'.format(flag_Q, flag_sep, ','.join(str(i) for i in warn_ids))] + # Disables diagnostic information reported by the vectorizer + if compiler_version >= Version('15.0'): + CFLAGS += ['{}diag-disable{}vec'.format(flag_Q, flag_sep)] + else: + CFLAGS += ['{}vec-report{}0'.format(flag_Q, flag_sep)] + + if system.is_windows and (Version(env['MSVC_VERSION']) == Version('14.0')) \ + and compiler_version >= Version('15.0.4'): + # Visual Studio 2015 Update 1 changed some builtin intrinsics into + # macros, giving some errors about undefined symbols when using icc 15 and 16 + # https://software.intel.com/en-us/articles/limits1120-error-identifier-builtin-nanf-is-undefined + # This was fixed in icc 16.0.2 + if compiler_version < Version('16.0.2'): + CPPDEFS += [{'__builtin_huge_val()' : 'HUGE_VAL' }] + CPPDEFS += [{'__builtin_huge_valf()': 'HUGE_VALF'}] + CPPDEFS += [{'__builtin_nan' : 'nan' }] + CPPDEFS += [{'__builtin_nanf' : 'nanf' }] + CPPDEFS += [{'__builtin_nans' : 'nan' }] + CPPDEFS += [{'__builtin_nansf' : 'nanf' }] + # Visual Studio 2015 Update 2 introduced a new syntax "__is_assignable" that Intel + # Compiler 16.0 update 2 doesn't yet support. This should be fixed in update 3. Until + # then we can work around it by defining a corresponding macro. See here for more info: + # https://software.intel.com/en-us/forums/intel-c-compiler/topic/623368 + # This was fixed in icc 16.0.3 + if compiler_version < Version('16.0.3'): + CPPDEFS += [{'__is_assignable': '__is_trivially_assignable'}] + + if system.is_windows: + # disables some CRT secure warnings. For the time being this is disabling + # warning 1786 for the deprecated function sprintf() + CPPDEFS += ['_CRT_SECURE_NO_WARNINGS'] + # Since we are not generating debug info when manually compiling the + # external libraries we need this flag in order to disable whe linker + # warning LNK4099 "PDB 'filename' was not found with 'object/library' or + # at 'path'; linking object as if no debug info". + LDFLAGS += ['ignore:4099'] + + # Enable colors in warning and error diagnostics + if env['COLOR_CMDS']: + if compiler_name == 'clang': + CFLAGS += ['fcolor-diagnostics'] + elif compiler_name == 'gcc' and compiler_version >= Version('4.9'): + CFLAGS += ['fdiagnostics-color'] + + if compiler_name == 'icc': + # NOTE (#3323): Tell the compiler to display certain information to the + # console output window. In this case do not display the name of the file + # being compiled + CFLAGS += ['watch:nosource'] + + if env['SHOW_CMDS'] and not system.is_windows: + # NOTE (#5196): Tell the compiler to show commands to run and use verbose + # output. + CFLAGS +=['v'] + LDFLAGS +=['v'] + + ## Compiler optimizations ################################################### + if env['MODE'] in ['opt', 'profile', 'dev']: + # NOTE (#3855): clang's "-O4" flag has been always equivalent to + # "-O3 -flto". But from version 3.4 "-O4" was removed. So we better use + # the common denominator + CFLAGS += ['O3'] + # In icc enable additional interprocedural optimizations for single-file + # compilation. + CFLAGS += ['{}ip'.format(flag_Q)] if compiler_name in ['icc'] else [] + + elif env['MODE'] in ['debug']: + # In debug mode we will disable all optimizations (-O0 in Linux/OSX and + # /Od in windows) + CFLAGS += ['O{}'.format('0' if not system.is_windows else 'd')] + + # Unroll loops whose number of iterations can be determined at compile time + # or upon entry to the loop. Do it in 'opt' and 'profile' modes. icc has the + # alternate notation /Qunroll, -unroll for Windows and Linux/OSX platforms. + if env['MODE'] in ['opt', 'profile']: + CFLAGS += { + 'gcc' : ['funroll-loops'], + 'clang': ['funroll-loops'], + 'icc' : ['{}unroll'.format(flag_Q)], + }.get(compiler_name, []) + + # NOTE (#4228): Disabling math errno checks in non-debug builds improve + # performance since we never use errno. This flag is available for gcc, clang + # and icc in Linux/OSX + if not system.is_windows: + CFLAGS += ['f{}math-errno'.format(enable_in('debug'))] + + # Improve the consistency of floating-point tests for equality and + # inequality by disabling optimizations that could change the precision of + # floating-point calculations. This flag is only available in icc and msvc. + flag_fm = 'fp{}{}precise' + if system.is_windows: CFLAGS += [flag_fm.format('' , flag_sep)] + elif compiler_name == 'icc': CFLAGS += [flag_fm.format('-model', flag_sep)] + + # Improves floating-point consistency. It ensures out-of-range check of + # operands of transcendental functions and improves the accuracy of + # floating-point compares. This option disables fewer optimizations and + # has less impact on performance than /fp:precise. This flag is only + # available in icc. + if compiler_name == 'icc': + CFLAGS += ['Qprec' if system.is_windows else 'mp1'] + + # NOTE (#3662): In non-'debug' modes, we disable the generation of code that + # detects some types of buffer overruns that overwrite a function's return + # address, exception handler address, or certain types of parameters, to gain + # a significant performance gain. + flag_sp = 'GS{}' if system.is_windows else 'f{}stack-protector' + CFLAGS += [flag_sp.format(enable_in('debug'))] + + # NOTE (#3607): If we are generating an 'opt' build, don't keep the frame + # pointer in a general-purpose register for functions that don't need one. + # This avoids the instructions to save, set up and restore frame pointers; it + # also makes an extra register available in many functions. + # This flag is /Oy[-] in Windows and -f[no-]omit-frame-pointer in Linux/OSX + # This flag is also automatically enabled/disabled in certain -O + # optimization levels, but we prefer to explicitly specify it. + flag_fp = 'Oy{}' if system.is_windows else 'f{}omit-frame-pointer' + CFLAGS += [flag_fp.format(enable_in('opt'))] + + ## Linker optimizations ##################################################### + + # Make clang linker always use the LLVM Gold plugin, in order to understand + # byte code object files from external static libraries + if compiler_name in ['clang'] and system.is_linux: + LDFLAGS += ['Wl,-plugin={LLVM_GOLD_PLUGIN}'.format(**env_dict)] + LDFLAGS += ['Wl,-plugin-opt=mcpu=x86-64'] + + if env['MODE'] in ['opt', 'profile']: + + if compiler_name in ['gcc', 'clang']: + if compiler_name in ['clang']: + CFLAGS += ['flto'] + # FIXME: Disabled LTO in GCC: + # Currently, GCC does not support combining LTO object files compiled + # with different set of the command line options into a single binary. + # So we will get linker errors due to precompiled external libs. + # NOTE: we can re-enable this, once externals can be built within SCons + if False: + if compiler_name in ['gcc']: + # Use the ld.gold for using the LTO plugin + LDFLAGS += ['Wl,-fuse-ld=gold'] + # Use wrapper tools for LTO support to pass a plugin to the + # ar/nm/ranlib programs + # NOTE: this should be moved to the GCC detection section + for i in ('NM', 'AR', 'RANLIB'): + tool = 'gcc-{0}'.format(i.lower()) + if env.Detect(tool): + env[i] = tool + CFLAGS += ['flto'] + LDFLAGS += ['Wl,-flto'] + + if compiler_name in ['icc']: + # Enable interprocedural optimization between files (multifile IPO). + # The compiler will perform inline function expansion for calls to + # functions defined in separate files. + CFLAGS += ['{}ipo'.format(flag_Q)] + + if system.is_windows: + # Eliminates functions and data that are never referenced (REF) ands + # perform identical COMDAT folding (ICF). + LDFLAGS += ['OPT:REF,ICF'] + + ## Platform optimizations ################################################### + # Indicate to the compiler the feature set that it may target, including + # which instruction sets it may generate. + # NOTE (#5665): We moved to SSE 4.1 + instruction_set = env['INSTRUCTION_SET'] + + # NOTE (#5476): We have to revert to SSE4.1 in windows due to a bug detected + # in icc 16.0.3, which is also present in icc 17.0.0 (see comment:7) + affected_by_5476 = ['16.0.3', '16.0.4', '17.0.0', '17.0.1'] + if system.is_windows and (instruction_set == 'sse4.2') and (compiler_name == 'icc') and \ + (compiler_version in [Version(x) for x in affected_by_5476]): + instruction_set = 'sse4.1' + + if system.is_darwin : CFLAGS += ['m{}'.format(instruction_set)] + if system.is_linux : CFLAGS += ['m{}'.format(instruction_set)] + if system.is_windows: CFLAGS += ['arch:{}'.format(instruction_set.upper())] + + ## General platform related options ######################################### + if system.is_windows: + CPPDEFS += ['_WINDOWS', '_WIN32', 'WIN32', '_WIN64'] + + # We explicitly target Windows 7 + windows_version = '7' + windows_target = { + '10' : 0x0A000000, # Windows 10 + '8.1' : 0x06030000, # Windows 8.1 + '8' : 0x06020000, # Windows 8 + '7' : 0x06010000, # Windows 7 + 'vista': 0x06000000, # Windows Vista + 'xp' : 0x05010000, # Windows XP + }.get(windows_version) + CPPDEFS += [{'NTDDI_VERSION' : hex(windows_target)}] + CPPDEFS += [{'_WIN32_WINNT' : hex(windows_target >> 16)}] + + CPPDEFS += [{'OIIO_STATIC_BUILD' : 1}] + CPPDEFS += ['PERFTOOLS_DLL_DECL'] + + # Disable checked iterators + CPPDEFS += [{'_SECURE_SCL' : 0}] + # Causes the application to use the NON-DEBUG multithread-specific and + # DLL-specific version of the run-time library. Defines "_MT" and "_DLL" + # and causes the compiler to place the library name MSVCRT.lib into the + # .obj file. Applications compiled with this option are statically linked + # to MSVCRT.lib. This library provides a layer of code that enables the + # linker to resolve external references. The actual working code is + # contained in MSVCR.DLL, which must be available at run + # time to applications linked with MSVCRT.lib. + CFLAGS += ['MD'] + # Enable the ISO-standard C++ exception-handling model that catches C++ + # exceptions only and tells the compiler to assume that functions declared + # as extern "C" never throw a C++ exception. + CFLAGS += ['EHsc'] + + # Generates complete debug information. In opt and profile modes we will + # generate it in a separate .pdb file, while in dev and debug modes it + # will be included in the object files. + if env['MODE'] in ['opt', 'profile']: + CFLAGS += ['debug:full' if compiler_name == 'icc' else 'Zi'] + elif env['MODE'] in ['dev', 'debug']: + CFLAGS += ['Z7'] + + # Controls how the linker handles incremental linking. We just want an + # incremental link in 'debug' mode. Otherwise we will perform a full link + if env['MODE'] in ['opt', 'profile', 'dev']: + LDFLAGS += ['INCREMENTAL:NO'] + else: + LDFLAGS += ['INCREMENTAL'] + # Tell the linker that the application can handle addresses larger than + # 2 gigabytes. In the 64-bit compilers, this option is enabled by default, + # FIXME: So maybe it's useless at this point? + LDFLAGS += ['LARGEADDRESSAWARE'] + # Specifys that the linker should create a side-by-side manifest file. + LDFLAGS += ['MANIFEST'] + # Exclude mmd, cmt and svml from the list of default libraries. We will use ... + # ... libmmd from contrib/IntelC++/lib when building arnold with '/MD' + # ... libcmt from contrib/tcmalloc/lib when building arnold with tcmalloc + # and '/MT' + # ... svml_dispmd from contrib/IntelC++/lib when building arnold with '/MD' + LDFLAGS += ['NODEFAULTLIB:libmmd'] + LDFLAGS += ['NODEFAULTLIB:libirc'] + LDFLAGS += ['NODEFAULTLIB:libcmt'] + LDFLAGS += ['NODEFAULTLIB:svml_dispmd'] + # Tell the linker to put the debugging information into a program database + # (.PDB) + LDFLAGS += ['DEBUG'] + else: + # NOTE (#2827): Always include all debugging symbols and extra + # information, such as all the macro definitions. We will strip them all + # after dumping the symbol table. + # In windows, icc/msvc have the equivalent /Z7, but we are currently using + # /debug:full (/Zi) for generating debug info in a project database (PDB) + # file + CFLAGS += ['g3'] + LDFLAGS += ['g3'] + + if system.is_darwin: + CPPDEFS += ['_DARWIN'] + CPPDEFS += ['_DARWIN_UNLIMITED_STREAMS'] # so we can change number of file handles (#5236) + # Minimum compatibility with Mac OSX 10.8 + CFLAGS += ['mmacosx-version-min=10.8'] + LDFLAGS += ['mmacosx-version-min=10.8'] + CFLAGS += ['isysroot {SDK_PATH}/MacOSX{SDK_VERSION}.sdk/'.format(**env_dict)] + LDFLAGS += ['isysroot {SDK_PATH}/MacOSX{SDK_VERSION}.sdk/'.format(**env_dict)] + LDFLAGS += ['framework CoreServices'] + # leave some room to change dylib paths with install_name_tool + LDFLAGS += ['headerpad_max_install_names'] + + if system.is_linux: + CPPDEFS += ['_LINUX'] + # Hide all internal symbols (the ones without AI_API decoration) + # FIXME (#4133): Symbols should be hidden on OSX as well. + CFLAGS += ['fvisibility=hidden'] + LDFLAGS += ['fvisibility=hidden'] + # Hide all symbols imported from external static libraries. + # Flag '-Wl,--exclude-libs,ALL' is only supported in linux. + # NOTE (#2294, #2632): We don't use '-Wl,-s' option anymore, since we can + # do it as a post-process with the 'strip -s' command + LDFLAGS += ['Wl,--exclude-libs,librlm.a:libOpenImageIO.a:libOpenColorIO.a'] + # Hardcode '.' directory in RPATH in linux + # NOTE (#4219): In order to use the RPATH (instead of the RUNPATH) in + # newer linkers we have to specifically use the flag --disable-new-dtags + RPATH += [env.Literal('\\$$ORIGIN')] + LDFLAGS += ['Wl,--disable-new-dtags'] + + ## Misc. options ############################################################ + + if compiler_name in ['icc']: + # Statically link Intel libraries so our libraries work on machines + # without intel redistributables + if not system.is_windows: + LDFLAGS += ['static-intel'] + # ... But we don't want Intel C/C++ language extensions such as array + # notation, Cilk, etc. since with some compiler version we get some known + # issues, such as warning #10237 + flag_ie = '{{}}intel-extensions{}' if system.is_windows else '{{}}{}intel-extensions' + CFLAGS += [flag_ie.format(flag_neg).format(flag_Q)] + if not system.is_windows: + LDFLAGS += [flag_ie.format(flag_neg).format(flag_Q)] + + if env['MODE'] == 'opt': + ## NOTE (#3305): We redefine these macros in order to not leak internal + ## paths and functions. This will also raise compiler warnings #2011 (icc) + ## and -Wbuiltin-macro-redefined (gcc) + CPPDEFS += [{'__AI_FILE__' : '\\"?\\"'}] + CPPDEFS += [{'__AI_LINE__' : '0' }] + CPPDEFS += [{'__AI_FUNCTION__' : '\\"?\\"'}] + + if env['MODE'] == 'debug': + CPPDEFS += ['ARNOLD_DEBUG'] + + if not env['ASSERTS']: + CPPDEFS += ['NDEBUG'] + + if env['USE_CLM']: + CPPDEFS += ['AI_CONFIG_LICENSE_CLM'] + if env['USE_AZURE'] and not system.is_darwin: + CPPDEFS += ['AI_CONFIG_LICENSE_AZURE'] + + ## Sanitizers ############################################################### + if env['SANITIZE']: + # Supported sanitizers: + # - address : memory error detector : http://clang.llvm.org/docs/AddressSanitizer.html + # - leak : memory leak detector : http://clang.llvm.org/docs/LeakSanitizer.html + # - memory : uninitialized reads detector : http://clang.llvm.org/docs/MemorySanitizer.html + # - undefined : undefined behavior detector : http://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html + # - thread : data races detector : http://clang.llvm.org/docs/ThreadSanitizer.html + + sanitize_error_string = [ + 'SANITIZE only allowed with COMPILER \'clang\' and \'gcc\'', + 'SANITIZE only allowed with MODE \'debug\'', + 'SANITIZE only allowed with MALLOC \'system\'', + ] + sanitize_error = None + + if compiler_name not in ['clang', 'gcc']: sanitize_error = 0 + elif env['MODE'] != 'debug' : sanitize_error = 1 + elif env['MALLOC'] != 'system' : sanitize_error = 2 + + if sanitize_error is not None: + raise SCons.Errors.UserError(sanitize_error_string[sanitize_error]) + + # Enable the selected sanitizer + flag_san = 'fsanitize={}'.format(env['SANITIZE']) + CFLAGS += [flag_san] + LDFLAGS += [flag_san] + + # suppressions for the leak sanitizer + def leak_supp_file(): + # Suppress reports from some external libraries + lsan_supp = ['OpenColorIO::', 'OpenImageIO::', 'Imf::', 'Ptex*::', 'cineon::', 'dpx::'] + # Create a temporary file for storing all the suppressions + f_lsan_supp = tempfile.NamedTemporaryFile(suffix='.supp', delete=False) + f_lsan_supp.writelines('leak:{}\n'.format(item) for item in lsan_supp) + f_lsan_supp.close() + # return the temporal filename + return f_lsan_supp.name + + # Environment variables for configuring every sanitizer at runtime + sanitizer_options_env = { + 'address' : 'ASAN_OPTIONS', + 'leak' : 'LSAN_OPTIONS', + 'memory' : 'MSAN_OPTIONS', + 'undefined': 'UBSAN_OPTIONS', + }.get(env['SANITIZE']) + + # Runtime configuration for every sanitizer + sanitizer_options = { + 'address': { + 'check_initialization_order' : 1, + 'detect_leaks' : 0, + }, + 'leak': { + 'suppressions' : leak_supp_file(), + 'print_suppressions' : 0, + }, + 'undefined': { + 'print_stacktrace' : 1, + }, + }.get(env['SANITIZE'], {}) + + # Setup the sanitizer runtime options + if sanitizer_options_env: + items = sanitizer_options.items() + string = ','.join('{}={}'.format(k, v) for k, v in items) + env['ENV'][sanitizer_options_env] = string + + # Define some macros for configuring sanitazion in the code + def attribute(x) : return '__attribute__\(\({}\)\)'.format(x) + def no_sanitize(x): return 'no_sanitize\(\\"{}\\"\)'.format(x) + CPPDEFS += [{'__AI_ATTRIBUTE_NO_SANITIZE_ADDRESS__': attribute(no_sanitize('address')) if env['SANITIZE'] == 'address' else ''}] + + if env['CODE_COVERAGE']: + # Enable Clang's source-based code coverage: It operates on AST and + # preprocessor information directly. This allows it to generate very precise + # coverage data + # http://releases.llvm.org/4.0.0/tools/clang/docs/SourceBasedCodeCoverage.html + CFLAGS += ['fprofile-instr-generate=arnold.profraw', 'fcoverage-mapping'] + LDFLAGS += ['fprofile-instr-generate=arnold.profraw', 'fcoverage-mapping'] + + ## Append all the pre-processor / compiler / linker flags to the SCons + ## construction environment. We first preprocess CFLAGS, CXXFLAGS and LDFLAGS + ## by prefixing them with a leading '/' or '-', depending on the platform. + def map_flag_prefix(flags, prefix): + for i in xrange(len(flags)): + flags[i] = env.Split(prefix + flags[i]) + + map_flag_prefix(CFLAGS , flag_prefix) + map_flag_prefix(CXXFLAGS, flag_prefix) + map_flag_prefix(LDFLAGS , flag_prefix) + + # Instead of using an env.Append() call for every list of flags (CFLAGS, + # CXXFLAGS, etc.), we can use the collected dictionary for adding all of them + # in a row with just one call. + env.Append(**compiler_flags) diff --git a/tools/utils/configure.py b/tools/utils/configure.py new file mode 100755 index 0000000000..b51b6196c8 --- /dev/null +++ b/tools/utils/configure.py @@ -0,0 +1,47 @@ +# Copyright 2019 Autodesk, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from string import Template + +from build_tools import convert_usd_version_to_int + +class DotTemplate(Template): + delimiter = '$' + idpattern = r'[_a-z][_a-z0-9\.]*' + +def configure(source, target, env, config): + with open(source[0].get_abspath(), 'r') as src: + src_contents = src.read() + with open(target[0].get_abspath(), 'w') as trg: + template = DotTemplate(src_contents) + trg.write(template.substitute(config)) + +def configure_plug_info(source, target, env): + import system + usd_version = convert_usd_version_to_int(env['USD_VERSION']) + configure(source, target, env, { + 'LIB_EXTENSION': system.LIB_EXTENSION, + 'RENDERER_PLUGIN_BASE': 'HdRendererPlugin' if usd_version >= 1910 else 'HdxRendererPlugin' + }) + +def configure_header_file(source, target, env): + usd_version = env['USD_VERSION'].split('.') + arnold_version = env['ARNOLD_VERSION'].split('.') + configure(source, target, env, { + 'USD_MAJOR_VERSION': usd_version[0], + 'USD_MINOR_VERSION': usd_version[1], + 'USD_PATCH_VERSION': usd_version[2], + 'ARNOLD_VERSION_ARCH_NUM': arnold_version[0], + 'ARNOLD_VERSION_MAJOR_NUM': arnold_version[1], + 'ARNOLD_VERSION_MINOR_NUM': arnold_version[2], + }) diff --git a/tools/utils/contrib/__init__.py b/tools/utils/contrib/__init__.py new file mode 100755 index 0000000000..e69de29bb2 diff --git a/tools/utils/contrib/beautiful_soup/__init__.py b/tools/utils/contrib/beautiful_soup/__init__.py new file mode 100755 index 0000000000..7278215ca2 --- /dev/null +++ b/tools/utils/contrib/beautiful_soup/__init__.py @@ -0,0 +1,2017 @@ +"""Beautiful Soup +Elixir and Tonic +"The Screen-Scraper's Friend" +http://www.crummy.com/software/BeautifulSoup/ + +Beautiful Soup parses a (possibly invalid) XML or HTML document into a +tree representation. It provides methods and Pythonic idioms that make +it easy to navigate, search, and modify the tree. + +A well-formed XML/HTML document yields a well-formed data +structure. An ill-formed XML/HTML document yields a correspondingly +ill-formed data structure. If your document is only locally +well-formed, you can use this library to find and process the +well-formed part of it. + +Beautiful Soup works with Python 2.2 and up. It has no external +dependencies, but you'll have more success at converting data to UTF-8 +if you also install these three packages: + +* chardet, for auto-detecting character encodings + http://chardet.feedparser.org/ +* cjkcodecs and iconv_codec, which add more encodings to the ones supported + by stock Python. + http://cjkpython.i18n.org/ + +Beautiful Soup defines classes for two main parsing strategies: + + * BeautifulStoneSoup, for parsing XML, SGML, or your domain-specific + language that kind of looks like XML. + + * BeautifulSoup, for parsing run-of-the-mill HTML code, be it valid + or invalid. This class has web browser-like heuristics for + obtaining a sensible parse tree in the face of common HTML errors. + +Beautiful Soup also defines a class (UnicodeDammit) for autodetecting +the encoding of an HTML or XML document, and converting it to +Unicode. Much of this code is taken from Mark Pilgrim's Universal Feed Parser. + +For more than you ever wanted to know about Beautiful Soup, see the +documentation: +http://www.crummy.com/software/BeautifulSoup/documentation.html + +Here, have some legalese: + +Copyright (c) 2004-2010, Leonard Richardson + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of the the Beautiful Soup Consortium and All + Night Kosher Bakery nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE, DAMMIT. + +""" +from __future__ import generators + +__author__ = "Leonard Richardson (leonardr@segfault.org)" +__version__ = "3.2.1" +__copyright__ = "Copyright (c) 2004-2012 Leonard Richardson" +__license__ = "New-style BSD" + +from sgmllib import SGMLParser, SGMLParseError +import codecs +import markupbase +import types +import re +import sgmllib +try: + from htmlentitydefs import name2codepoint +except ImportError: + name2codepoint = {} +try: + set +except NameError: + from sets import Set as set + +#These hacks make Beautiful Soup able to parse XML with namespaces +sgmllib.tagfind = re.compile('[a-zA-Z][-_.:a-zA-Z0-9]*') +markupbase._declname_match = re.compile(r'[a-zA-Z][-_.:a-zA-Z0-9]*\s*').match + +DEFAULT_OUTPUT_ENCODING = "utf-8" + +def _match_css_class(str): + """Build a RE to match the given CSS class.""" + return re.compile(r"(^|.*\s)%s($|\s)" % str) + +# First, the classes that represent markup elements. + +class PageElement(object): + """Contains the navigational information for some part of the page + (either a tag or a piece of text)""" + + def _invert(h): + "Cheap function to invert a hash." + i = {} + for k,v in h.items(): + i[v] = k + return i + + XML_ENTITIES_TO_SPECIAL_CHARS = { "apos" : "'", + "quot" : '"', + "amp" : "&", + "lt" : "<", + "gt" : ">" } + + XML_SPECIAL_CHARS_TO_ENTITIES = _invert(XML_ENTITIES_TO_SPECIAL_CHARS) + + def setup(self, parent=None, previous=None): + """Sets up the initial relations between this element and + other elements.""" + self.parent = parent + self.previous = previous + self.next = None + self.previousSibling = None + self.nextSibling = None + if self.parent and self.parent.contents: + self.previousSibling = self.parent.contents[-1] + self.previousSibling.nextSibling = self + + def replaceWith(self, replaceWith): + oldParent = self.parent + myIndex = self.parent.index(self) + if hasattr(replaceWith, "parent")\ + and replaceWith.parent is self.parent: + # We're replacing this element with one of its siblings. + index = replaceWith.parent.index(replaceWith) + if index and index < myIndex: + # Furthermore, it comes before this element. That + # means that when we extract it, the index of this + # element will change. + myIndex = myIndex - 1 + self.extract() + oldParent.insert(myIndex, replaceWith) + + def replaceWithChildren(self): + myParent = self.parent + myIndex = self.parent.index(self) + self.extract() + reversedChildren = list(self.contents) + reversedChildren.reverse() + for child in reversedChildren: + myParent.insert(myIndex, child) + + def extract(self): + """Destructively rips this element out of the tree.""" + if self.parent: + try: + del self.parent.contents[self.parent.index(self)] + except ValueError: + pass + + #Find the two elements that would be next to each other if + #this element (and any children) hadn't been parsed. Connect + #the two. + lastChild = self._lastRecursiveChild() + nextElement = lastChild.next + + if self.previous: + self.previous.next = nextElement + if nextElement: + nextElement.previous = self.previous + self.previous = None + lastChild.next = None + + self.parent = None + if self.previousSibling: + self.previousSibling.nextSibling = self.nextSibling + if self.nextSibling: + self.nextSibling.previousSibling = self.previousSibling + self.previousSibling = self.nextSibling = None + return self + + def _lastRecursiveChild(self): + "Finds the last element beneath this object to be parsed." + lastChild = self + while hasattr(lastChild, 'contents') and lastChild.contents: + lastChild = lastChild.contents[-1] + return lastChild + + def insert(self, position, newChild): + if isinstance(newChild, basestring) \ + and not isinstance(newChild, NavigableString): + newChild = NavigableString(newChild) + + position = min(position, len(self.contents)) + if hasattr(newChild, 'parent') and newChild.parent is not None: + # We're 'inserting' an element that's already one + # of this object's children. + if newChild.parent is self: + index = self.index(newChild) + if index > position: + # Furthermore we're moving it further down the + # list of this object's children. That means that + # when we extract this element, our target index + # will jump down one. + position = position - 1 + newChild.extract() + + newChild.parent = self + previousChild = None + if position == 0: + newChild.previousSibling = None + newChild.previous = self + else: + previousChild = self.contents[position-1] + newChild.previousSibling = previousChild + newChild.previousSibling.nextSibling = newChild + newChild.previous = previousChild._lastRecursiveChild() + if newChild.previous: + newChild.previous.next = newChild + + newChildsLastElement = newChild._lastRecursiveChild() + + if position >= len(self.contents): + newChild.nextSibling = None + + parent = self + parentsNextSibling = None + while not parentsNextSibling: + parentsNextSibling = parent.nextSibling + parent = parent.parent + if not parent: # This is the last element in the document. + break + if parentsNextSibling: + newChildsLastElement.next = parentsNextSibling + else: + newChildsLastElement.next = None + else: + nextChild = self.contents[position] + newChild.nextSibling = nextChild + if newChild.nextSibling: + newChild.nextSibling.previousSibling = newChild + newChildsLastElement.next = nextChild + + if newChildsLastElement.next: + newChildsLastElement.next.previous = newChildsLastElement + self.contents.insert(position, newChild) + + def append(self, tag): + """Appends the given tag to the contents of this tag.""" + self.insert(len(self.contents), tag) + + def findNext(self, name=None, attrs={}, text=None, **kwargs): + """Returns the first item that matches the given criteria and + appears after this Tag in the document.""" + return self._findOne(self.findAllNext, name, attrs, text, **kwargs) + + def findAllNext(self, name=None, attrs={}, text=None, limit=None, + **kwargs): + """Returns all items that match the given criteria and appear + after this Tag in the document.""" + return self._findAll(name, attrs, text, limit, self.nextGenerator, + **kwargs) + + def findNextSibling(self, name=None, attrs={}, text=None, **kwargs): + """Returns the closest sibling to this Tag that matches the + given criteria and appears after this Tag in the document.""" + return self._findOne(self.findNextSiblings, name, attrs, text, + **kwargs) + + def findNextSiblings(self, name=None, attrs={}, text=None, limit=None, + **kwargs): + """Returns the siblings of this Tag that match the given + criteria and appear after this Tag in the document.""" + return self._findAll(name, attrs, text, limit, + self.nextSiblingGenerator, **kwargs) + fetchNextSiblings = findNextSiblings # Compatibility with pre-3.x + + def findPrevious(self, name=None, attrs={}, text=None, **kwargs): + """Returns the first item that matches the given criteria and + appears before this Tag in the document.""" + return self._findOne(self.findAllPrevious, name, attrs, text, **kwargs) + + def findAllPrevious(self, name=None, attrs={}, text=None, limit=None, + **kwargs): + """Returns all items that match the given criteria and appear + before this Tag in the document.""" + return self._findAll(name, attrs, text, limit, self.previousGenerator, + **kwargs) + fetchPrevious = findAllPrevious # Compatibility with pre-3.x + + def findPreviousSibling(self, name=None, attrs={}, text=None, **kwargs): + """Returns the closest sibling to this Tag that matches the + given criteria and appears before this Tag in the document.""" + return self._findOne(self.findPreviousSiblings, name, attrs, text, + **kwargs) + + def findPreviousSiblings(self, name=None, attrs={}, text=None, + limit=None, **kwargs): + """Returns the siblings of this Tag that match the given + criteria and appear before this Tag in the document.""" + return self._findAll(name, attrs, text, limit, + self.previousSiblingGenerator, **kwargs) + fetchPreviousSiblings = findPreviousSiblings # Compatibility with pre-3.x + + def findParent(self, name=None, attrs={}, **kwargs): + """Returns the closest parent of this Tag that matches the given + criteria.""" + # NOTE: We can't use _findOne because findParents takes a different + # set of arguments. + r = None + l = self.findParents(name, attrs, 1) + if l: + r = l[0] + return r + + def findParents(self, name=None, attrs={}, limit=None, **kwargs): + """Returns the parents of this Tag that match the given + criteria.""" + + return self._findAll(name, attrs, None, limit, self.parentGenerator, + **kwargs) + fetchParents = findParents # Compatibility with pre-3.x + + #These methods do the real heavy lifting. + + def _findOne(self, method, name, attrs, text, **kwargs): + r = None + l = method(name, attrs, text, 1, **kwargs) + if l: + r = l[0] + return r + + def _findAll(self, name, attrs, text, limit, generator, **kwargs): + "Iterates over a generator looking for things that match." + + if isinstance(name, SoupStrainer): + strainer = name + # (Possibly) special case some findAll*(...) searches + elif text is None and not limit and not attrs and not kwargs: + # findAll*(True) + if name is True: + return [element for element in generator() + if isinstance(element, Tag)] + # findAll*('tag-name') + elif isinstance(name, basestring): + return [element for element in generator() + if isinstance(element, Tag) and + element.name == name] + else: + strainer = SoupStrainer(name, attrs, text, **kwargs) + # Build a SoupStrainer + else: + strainer = SoupStrainer(name, attrs, text, **kwargs) + results = ResultSet(strainer) + g = generator() + while True: + try: + i = g.next() + except StopIteration: + break + if i: + found = strainer.search(i) + if found: + results.append(found) + if limit and len(results) >= limit: + break + return results + + #These Generators can be used to navigate starting from both + #NavigableStrings and Tags. + def nextGenerator(self): + i = self + while i is not None: + i = i.next + yield i + + def nextSiblingGenerator(self): + i = self + while i is not None: + i = i.nextSibling + yield i + + def previousGenerator(self): + i = self + while i is not None: + i = i.previous + yield i + + def previousSiblingGenerator(self): + i = self + while i is not None: + i = i.previousSibling + yield i + + def parentGenerator(self): + i = self + while i is not None: + i = i.parent + yield i + + # Utility methods + def substituteEncoding(self, str, encoding=None): + encoding = encoding or "utf-8" + return str.replace("%SOUP-ENCODING%", encoding) + + def toEncoding(self, s, encoding=None): + """Encodes an object to a string in some encoding, or to Unicode. + .""" + if isinstance(s, unicode): + if encoding: + s = s.encode(encoding) + elif isinstance(s, str): + if encoding: + s = s.encode(encoding) + else: + s = unicode(s) + else: + if encoding: + s = self.toEncoding(str(s), encoding) + else: + s = unicode(s) + return s + + BARE_AMPERSAND_OR_BRACKET = re.compile("([<>]|" + + "&(?!#\d+;|#x[0-9a-fA-F]+;|\w+;)" + + ")") + + def _sub_entity(self, x): + """Used with a regular expression to substitute the + appropriate XML entity for an XML special character.""" + return "&" + self.XML_SPECIAL_CHARS_TO_ENTITIES[x.group(0)[0]] + ";" + + +class NavigableString(unicode, PageElement): + + def __new__(cls, value): + """Create a new NavigableString. + + When unpickling a NavigableString, this method is called with + the string in DEFAULT_OUTPUT_ENCODING. That encoding needs to be + passed in to the superclass's __new__ or the superclass won't know + how to handle non-ASCII characters. + """ + if isinstance(value, unicode): + return unicode.__new__(cls, value) + return unicode.__new__(cls, value, DEFAULT_OUTPUT_ENCODING) + + def __getnewargs__(self): + return (NavigableString.__str__(self),) + + def __getattr__(self, attr): + """text.string gives you text. This is for backwards + compatibility for Navigable*String, but for CData* it lets you + get the string without the CData wrapper.""" + if attr == 'string': + return self + else: + raise AttributeError, "'%s' object has no attribute '%s'" % (self.__class__.__name__, attr) + + def __unicode__(self): + return str(self).decode(DEFAULT_OUTPUT_ENCODING) + + def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING): + # Substitute outgoing XML entities. + data = self.BARE_AMPERSAND_OR_BRACKET.sub(self._sub_entity, self) + if encoding: + return data.encode(encoding) + else: + return data + +class CData(NavigableString): + + def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING): + return "" % NavigableString.__str__(self, encoding) + +class ProcessingInstruction(NavigableString): + def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING): + output = self + if "%SOUP-ENCODING%" in output: + output = self.substituteEncoding(output, encoding) + return "" % self.toEncoding(output, encoding) + +class Comment(NavigableString): + def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING): + return "" % NavigableString.__str__(self, encoding) + +class Declaration(NavigableString): + def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING): + return "" % NavigableString.__str__(self, encoding) + +class Tag(PageElement): + + """Represents a found HTML tag with its attributes and contents.""" + + def _convertEntities(self, match): + """Used in a call to re.sub to replace HTML, XML, and numeric + entities with the appropriate Unicode characters. If HTML + entities are being converted, any unrecognized entities are + escaped.""" + x = match.group(1) + if self.convertHTMLEntities and x in name2codepoint: + return unichr(name2codepoint[x]) + elif x in self.XML_ENTITIES_TO_SPECIAL_CHARS: + if self.convertXMLEntities: + return self.XML_ENTITIES_TO_SPECIAL_CHARS[x] + else: + return u'&%s;' % x + elif len(x) > 0 and x[0] == '#': + # Handle numeric entities + if len(x) > 1 and x[1] == 'x': + return unichr(int(x[2:], 16)) + else: + return unichr(int(x[1:])) + + elif self.escapeUnrecognizedEntities: + return u'&%s;' % x + else: + return u'&%s;' % x + + def __init__(self, parser, name, attrs=None, parent=None, + previous=None): + "Basic constructor." + + # We don't actually store the parser object: that lets extracted + # chunks be garbage-collected + self.parserClass = parser.__class__ + self.isSelfClosing = parser.isSelfClosingTag(name) + self.name = name + if attrs is None: + attrs = [] + elif isinstance(attrs, dict): + attrs = attrs.items() + self.attrs = attrs + self.contents = [] + self.setup(parent, previous) + self.hidden = False + self.containsSubstitutions = False + self.convertHTMLEntities = parser.convertHTMLEntities + self.convertXMLEntities = parser.convertXMLEntities + self.escapeUnrecognizedEntities = parser.escapeUnrecognizedEntities + + # Convert any HTML, XML, or numeric entities in the attribute values. + convert = lambda(k, val): (k, + re.sub("&(#\d+|#x[0-9a-fA-F]+|\w+);", + self._convertEntities, + val)) + self.attrs = map(convert, self.attrs) + + def getString(self): + if (len(self.contents) == 1 + and isinstance(self.contents[0], NavigableString)): + return self.contents[0] + + def setString(self, string): + """Replace the contents of the tag with a string""" + self.clear() + self.append(string) + + string = property(getString, setString) + + def getText(self, separator=u""): + if not len(self.contents): + return u"" + stopNode = self._lastRecursiveChild().next + strings = [] + current = self.contents[0] + while current is not stopNode: + if isinstance(current, NavigableString): + strings.append(current.strip()) + current = current.next + return separator.join(strings) + + text = property(getText) + + def get(self, key, default=None): + """Returns the value of the 'key' attribute for the tag, or + the value given for 'default' if it doesn't have that + attribute.""" + return self._getAttrMap().get(key, default) + + def clear(self): + """Extract all children.""" + for child in self.contents[:]: + child.extract() + + def index(self, element): + for i, child in enumerate(self.contents): + if child is element: + return i + raise ValueError("Tag.index: element not in tag") + + def has_key(self, key): + return self._getAttrMap().has_key(key) + + def __getitem__(self, key): + """tag[key] returns the value of the 'key' attribute for the tag, + and throws an exception if it's not there.""" + return self._getAttrMap()[key] + + def __iter__(self): + "Iterating over a tag iterates over its contents." + return iter(self.contents) + + def __len__(self): + "The length of a tag is the length of its list of contents." + return len(self.contents) + + def __contains__(self, x): + return x in self.contents + + def __nonzero__(self): + "A tag is non-None even if it has no contents." + return True + + def __setitem__(self, key, value): + """Setting tag[key] sets the value of the 'key' attribute for the + tag.""" + self._getAttrMap() + self.attrMap[key] = value + found = False + for i in range(0, len(self.attrs)): + if self.attrs[i][0] == key: + self.attrs[i] = (key, value) + found = True + if not found: + self.attrs.append((key, value)) + self._getAttrMap()[key] = value + + def __delitem__(self, key): + "Deleting tag[key] deletes all 'key' attributes for the tag." + for item in self.attrs: + if item[0] == key: + self.attrs.remove(item) + #We don't break because bad HTML can define the same + #attribute multiple times. + self._getAttrMap() + if self.attrMap.has_key(key): + del self.attrMap[key] + + def __call__(self, *args, **kwargs): + """Calling a tag like a function is the same as calling its + findAll() method. Eg. tag('a') returns a list of all the A tags + found within this tag.""" + return apply(self.findAll, args, kwargs) + + def __getattr__(self, tag): + #print "Getattr %s.%s" % (self.__class__, tag) + if len(tag) > 3 and tag.rfind('Tag') == len(tag)-3: + return self.find(tag[:-3]) + elif tag.find('__') != 0: + return self.find(tag) + raise AttributeError, "'%s' object has no attribute '%s'" % (self.__class__, tag) + + def __eq__(self, other): + """Returns true iff this tag has the same name, the same attributes, + and the same contents (recursively) as the given tag. + + NOTE: right now this will return false if two tags have the + same attributes in a different order. Should this be fixed?""" + if other is self: + return True + if not hasattr(other, 'name') or not hasattr(other, 'attrs') or not hasattr(other, 'contents') or self.name != other.name or self.attrs != other.attrs or len(self) != len(other): + return False + for i in range(0, len(self.contents)): + if self.contents[i] != other.contents[i]: + return False + return True + + def __ne__(self, other): + """Returns true iff this tag is not identical to the other tag, + as defined in __eq__.""" + return not self == other + + def __repr__(self, encoding=DEFAULT_OUTPUT_ENCODING): + """Renders this tag as a string.""" + return self.__str__(encoding) + + def __unicode__(self): + return self.__str__(None) + + def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING, + prettyPrint=False, indentLevel=0): + """Returns a string or Unicode representation of this tag and + its contents. To get Unicode, pass None for encoding. + + NOTE: since Python's HTML parser consumes whitespace, this + method is not certain to reproduce the whitespace present in + the original string.""" + + encodedName = self.toEncoding(self.name, encoding) + + attrs = [] + if self.attrs: + for key, val in self.attrs: + fmt = '%s="%s"' + if isinstance(val, basestring): + if self.containsSubstitutions and '%SOUP-ENCODING%' in val: + val = self.substituteEncoding(val, encoding) + + # The attribute value either: + # + # * Contains no embedded double quotes or single quotes. + # No problem: we enclose it in double quotes. + # * Contains embedded single quotes. No problem: + # double quotes work here too. + # * Contains embedded double quotes. No problem: + # we enclose it in single quotes. + # * Embeds both single _and_ double quotes. This + # can't happen naturally, but it can happen if + # you modify an attribute value after parsing + # the document. Now we have a bit of a + # problem. We solve it by enclosing the + # attribute in single quotes, and escaping any + # embedded single quotes to XML entities. + if '"' in val: + fmt = "%s='%s'" + if "'" in val: + # TODO: replace with apos when + # appropriate. + val = val.replace("'", "&squot;") + + # Now we're okay w/r/t quotes. But the attribute + # value might also contain angle brackets, or + # ampersands that aren't part of entities. We need + # to escape those to XML entities too. + val = self.BARE_AMPERSAND_OR_BRACKET.sub(self._sub_entity, val) + + attrs.append(fmt % (self.toEncoding(key, encoding), + self.toEncoding(val, encoding))) + close = '' + closeTag = '' + if self.isSelfClosing: + close = ' /' + else: + closeTag = '' % encodedName + + indentTag, indentContents = 0, 0 + if prettyPrint: + indentTag = indentLevel + space = (' ' * (indentTag-1)) + indentContents = indentTag + 1 + contents = self.renderContents(encoding, prettyPrint, indentContents) + if self.hidden: + s = contents + else: + s = [] + attributeString = '' + if attrs: + attributeString = ' ' + ' '.join(attrs) + if prettyPrint: + s.append(space) + s.append('<%s%s%s>' % (encodedName, attributeString, close)) + if prettyPrint: + s.append("\n") + s.append(contents) + if prettyPrint and contents and contents[-1] != "\n": + s.append("\n") + if prettyPrint and closeTag: + s.append(space) + s.append(closeTag) + if prettyPrint and closeTag and self.nextSibling: + s.append("\n") + s = ''.join(s) + return s + + def decompose(self): + """Recursively destroys the contents of this tree.""" + self.extract() + if len(self.contents) == 0: + return + current = self.contents[0] + while current is not None: + next = current.next + if isinstance(current, Tag): + del current.contents[:] + current.parent = None + current.previous = None + current.previousSibling = None + current.next = None + current.nextSibling = None + current = next + + def prettify(self, encoding=DEFAULT_OUTPUT_ENCODING): + return self.__str__(encoding, True) + + def renderContents(self, encoding=DEFAULT_OUTPUT_ENCODING, + prettyPrint=False, indentLevel=0): + """Renders the contents of this tag as a string in the given + encoding. If encoding is None, returns a Unicode string..""" + s=[] + for c in self: + text = None + if isinstance(c, NavigableString): + text = c.__str__(encoding) + elif isinstance(c, Tag): + s.append(c.__str__(encoding, prettyPrint, indentLevel)) + if text and prettyPrint: + text = text.strip() + if text: + if prettyPrint: + s.append(" " * (indentLevel-1)) + s.append(text) + if prettyPrint: + s.append("\n") + return ''.join(s) + + #Soup methods + + def find(self, name=None, attrs={}, recursive=True, text=None, + **kwargs): + """Return only the first child of this Tag matching the given + criteria.""" + r = None + l = self.findAll(name, attrs, recursive, text, 1, **kwargs) + if l: + r = l[0] + return r + findChild = find + + def findAll(self, name=None, attrs={}, recursive=True, text=None, + limit=None, **kwargs): + """Extracts a list of Tag objects that match the given + criteria. You can specify the name of the Tag and any + attributes you want the Tag to have. + + The value of a key-value pair in the 'attrs' map can be a + string, a list of strings, a regular expression object, or a + callable that takes a string and returns whether or not the + string matches for some custom definition of 'matches'. The + same is true of the tag name.""" + generator = self.recursiveChildGenerator + if not recursive: + generator = self.childGenerator + return self._findAll(name, attrs, text, limit, generator, **kwargs) + findChildren = findAll + + # Pre-3.x compatibility methods + first = find + fetch = findAll + + def fetchText(self, text=None, recursive=True, limit=None): + return self.findAll(text=text, recursive=recursive, limit=limit) + + def firstText(self, text=None, recursive=True): + return self.find(text=text, recursive=recursive) + + #Private methods + + def _getAttrMap(self): + """Initializes a map representation of this tag's attributes, + if not already initialized.""" + if not getattr(self, 'attrMap'): + self.attrMap = {} + for (key, value) in self.attrs: + self.attrMap[key] = value + return self.attrMap + + #Generator methods + def childGenerator(self): + # Just use the iterator from the contents + return iter(self.contents) + + def recursiveChildGenerator(self): + if not len(self.contents): + raise StopIteration + stopNode = self._lastRecursiveChild().next + current = self.contents[0] + while current is not stopNode: + yield current + current = current.next + + +# Next, a couple classes to represent queries and their results. +class SoupStrainer: + """Encapsulates a number of ways of matching a markup element (tag or + text).""" + + def __init__(self, name=None, attrs={}, text=None, **kwargs): + self.name = name + if isinstance(attrs, basestring): + kwargs['class'] = _match_css_class(attrs) + attrs = None + if kwargs: + if attrs: + attrs = attrs.copy() + attrs.update(kwargs) + else: + attrs = kwargs + self.attrs = attrs + self.text = text + + def __str__(self): + if self.text: + return self.text + else: + return "%s|%s" % (self.name, self.attrs) + + def searchTag(self, markupName=None, markupAttrs={}): + found = None + markup = None + if isinstance(markupName, Tag): + markup = markupName + markupAttrs = markup + callFunctionWithTagData = callable(self.name) \ + and not isinstance(markupName, Tag) + + if (not self.name) \ + or callFunctionWithTagData \ + or (markup and self._matches(markup, self.name)) \ + or (not markup and self._matches(markupName, self.name)): + if callFunctionWithTagData: + match = self.name(markupName, markupAttrs) + else: + match = True + markupAttrMap = None + for attr, matchAgainst in self.attrs.items(): + if not markupAttrMap: + if hasattr(markupAttrs, 'get'): + markupAttrMap = markupAttrs + else: + markupAttrMap = {} + for k,v in markupAttrs: + markupAttrMap[k] = v + attrValue = markupAttrMap.get(attr) + if not self._matches(attrValue, matchAgainst): + match = False + break + if match: + if markup: + found = markup + else: + found = markupName + return found + + def search(self, markup): + #print 'looking for %s in %s' % (self, markup) + found = None + # If given a list of items, scan it for a text element that + # matches. + if hasattr(markup, "__iter__") \ + and not isinstance(markup, Tag): + for element in markup: + if isinstance(element, NavigableString) \ + and self.search(element): + found = element + break + # If it's a Tag, make sure its name or attributes match. + # Don't bother with Tags if we're searching for text. + elif isinstance(markup, Tag): + if not self.text: + found = self.searchTag(markup) + # If it's text, make sure the text matches. + elif isinstance(markup, NavigableString) or \ + isinstance(markup, basestring): + if self._matches(markup, self.text): + found = markup + else: + raise Exception, "I don't know how to match against a %s" \ + % markup.__class__ + return found + + def _matches(self, markup, matchAgainst): + #print "Matching %s against %s" % (markup, matchAgainst) + result = False + if matchAgainst is True: + result = markup is not None + elif callable(matchAgainst): + result = matchAgainst(markup) + else: + #Custom match methods take the tag as an argument, but all + #other ways of matching match the tag name as a string. + if isinstance(markup, Tag): + markup = markup.name + if markup and not isinstance(markup, basestring): + markup = unicode(markup) + #Now we know that chunk is either a string, or None. + if hasattr(matchAgainst, 'match'): + # It's a regexp object. + result = markup and matchAgainst.search(markup) + elif hasattr(matchAgainst, '__iter__'): # list-like + result = markup in matchAgainst + elif hasattr(matchAgainst, 'items'): + result = markup.has_key(matchAgainst) + elif matchAgainst and isinstance(markup, basestring): + if isinstance(markup, unicode): + matchAgainst = unicode(matchAgainst) + else: + matchAgainst = str(matchAgainst) + + if not result: + result = matchAgainst == markup + return result + +class ResultSet(list): + """A ResultSet is just a list that keeps track of the SoupStrainer + that created it.""" + def __init__(self, source): + list.__init__([]) + self.source = source + +# Now, some helper functions. + +def buildTagMap(default, *args): + """Turns a list of maps, lists, or scalars into a single map. + Used to build the SELF_CLOSING_TAGS, NESTABLE_TAGS, and + NESTING_RESET_TAGS maps out of lists and partial maps.""" + built = {} + for portion in args: + if hasattr(portion, 'items'): + #It's a map. Merge it. + for k,v in portion.items(): + built[k] = v + elif hasattr(portion, '__iter__'): # is a list + #It's a list. Map each item to the default. + for k in portion: + built[k] = default + else: + #It's a scalar. Map it to the default. + built[portion] = default + return built + +# Now, the parser classes. + +class BeautifulStoneSoup(Tag, SGMLParser): + + """This class contains the basic parser and search code. It defines + a parser that knows nothing about tag behavior except for the + following: + + You can't close a tag without closing all the tags it encloses. + That is, "" actually means + "". + + [Another possible explanation is "", but since + this class defines no SELF_CLOSING_TAGS, it will never use that + explanation.] + + This class is useful for parsing XML or made-up markup languages, + or when BeautifulSoup makes an assumption counter to what you were + expecting.""" + + SELF_CLOSING_TAGS = {} + NESTABLE_TAGS = {} + RESET_NESTING_TAGS = {} + QUOTE_TAGS = {} + PRESERVE_WHITESPACE_TAGS = [] + + MARKUP_MASSAGE = [(re.compile('(<[^<>]*)/>'), + lambda x: x.group(1) + ' />'), + (re.compile(']*)>'), + lambda x: '') + ] + + ROOT_TAG_NAME = u'[document]' + + HTML_ENTITIES = "html" + XML_ENTITIES = "xml" + XHTML_ENTITIES = "xhtml" + # TODO: This only exists for backwards-compatibility + ALL_ENTITIES = XHTML_ENTITIES + + # Used when determining whether a text node is all whitespace and + # can be replaced with a single space. A text node that contains + # fancy Unicode spaces (usually non-breaking) should be left + # alone. + STRIP_ASCII_SPACES = { 9: None, 10: None, 12: None, 13: None, 32: None, } + + def __init__(self, markup="", parseOnlyThese=None, fromEncoding=None, + markupMassage=True, smartQuotesTo=XML_ENTITIES, + convertEntities=None, selfClosingTags=None, isHTML=False): + """The Soup object is initialized as the 'root tag', and the + provided markup (which can be a string or a file-like object) + is fed into the underlying parser. + + sgmllib will process most bad HTML, and the BeautifulSoup + class has some tricks for dealing with some HTML that kills + sgmllib, but Beautiful Soup can nonetheless choke or lose data + if your data uses self-closing tags or declarations + incorrectly. + + By default, Beautiful Soup uses regexes to sanitize input, + avoiding the vast majority of these problems. If the problems + don't apply to you, pass in False for markupMassage, and + you'll get better performance. + + The default parser massage techniques fix the two most common + instances of invalid HTML that choke sgmllib: + +
(No space between name of closing tag and tag close) + (Extraneous whitespace in declaration) + + You can pass in a custom list of (RE object, replace method) + tuples to get Beautiful Soup to scrub your input the way you + want.""" + + self.parseOnlyThese = parseOnlyThese + self.fromEncoding = fromEncoding + self.smartQuotesTo = smartQuotesTo + self.convertEntities = convertEntities + # Set the rules for how we'll deal with the entities we + # encounter + if self.convertEntities: + # It doesn't make sense to convert encoded characters to + # entities even while you're converting entities to Unicode. + # Just convert it all to Unicode. + self.smartQuotesTo = None + if convertEntities == self.HTML_ENTITIES: + self.convertXMLEntities = False + self.convertHTMLEntities = True + self.escapeUnrecognizedEntities = True + elif convertEntities == self.XHTML_ENTITIES: + self.convertXMLEntities = True + self.convertHTMLEntities = True + self.escapeUnrecognizedEntities = False + elif convertEntities == self.XML_ENTITIES: + self.convertXMLEntities = True + self.convertHTMLEntities = False + self.escapeUnrecognizedEntities = False + else: + self.convertXMLEntities = False + self.convertHTMLEntities = False + self.escapeUnrecognizedEntities = False + + self.instanceSelfClosingTags = buildTagMap(None, selfClosingTags) + SGMLParser.__init__(self) + + if hasattr(markup, 'read'): # It's a file-type object. + markup = markup.read() + self.markup = markup + self.markupMassage = markupMassage + try: + self._feed(isHTML=isHTML) + except StopParsing: + pass + self.markup = None # The markup can now be GCed + + def convert_charref(self, name): + """This method fixes a bug in Python's SGMLParser.""" + try: + n = int(name) + except ValueError: + return + if not 0 <= n <= 127 : # ASCII ends at 127, not 255 + return + return self.convert_codepoint(n) + + def _feed(self, inDocumentEncoding=None, isHTML=False): + # Convert the document to Unicode. + markup = self.markup + if isinstance(markup, unicode): + if not hasattr(self, 'originalEncoding'): + self.originalEncoding = None + else: + dammit = UnicodeDammit\ + (markup, [self.fromEncoding, inDocumentEncoding], + smartQuotesTo=self.smartQuotesTo, isHTML=isHTML) + markup = dammit.unicode + self.originalEncoding = dammit.originalEncoding + self.declaredHTMLEncoding = dammit.declaredHTMLEncoding + if markup: + if self.markupMassage: + if not hasattr(self.markupMassage, "__iter__"): + self.markupMassage = self.MARKUP_MASSAGE + for fix, m in self.markupMassage: + markup = fix.sub(m, markup) + # TODO: We get rid of markupMassage so that the + # soup object can be deepcopied later on. Some + # Python installations can't copy regexes. If anyone + # was relying on the existence of markupMassage, this + # might cause problems. + del(self.markupMassage) + self.reset() + + SGMLParser.feed(self, markup) + # Close out any unfinished strings and close all the open tags. + self.endData() + while self.currentTag.name != self.ROOT_TAG_NAME: + self.popTag() + + def __getattr__(self, methodName): + """This method routes method call requests to either the SGMLParser + superclass or the Tag superclass, depending on the method name.""" + #print "__getattr__ called on %s.%s" % (self.__class__, methodName) + + if methodName.startswith('start_') or methodName.startswith('end_') \ + or methodName.startswith('do_'): + return SGMLParser.__getattr__(self, methodName) + elif not methodName.startswith('__'): + return Tag.__getattr__(self, methodName) + else: + raise AttributeError + + def isSelfClosingTag(self, name): + """Returns true iff the given string is the name of a + self-closing tag according to this parser.""" + return self.SELF_CLOSING_TAGS.has_key(name) \ + or self.instanceSelfClosingTags.has_key(name) + + def reset(self): + Tag.__init__(self, self, self.ROOT_TAG_NAME) + self.hidden = 1 + SGMLParser.reset(self) + self.currentData = [] + self.currentTag = None + self.tagStack = [] + self.quoteStack = [] + self.pushTag(self) + + def popTag(self): + tag = self.tagStack.pop() + + #print "Pop", tag.name + if self.tagStack: + self.currentTag = self.tagStack[-1] + return self.currentTag + + def pushTag(self, tag): + #print "Push", tag.name + if self.currentTag: + self.currentTag.contents.append(tag) + self.tagStack.append(tag) + self.currentTag = self.tagStack[-1] + + def endData(self, containerClass=NavigableString): + if self.currentData: + currentData = u''.join(self.currentData) + if (currentData.translate(self.STRIP_ASCII_SPACES) == '' and + not set([tag.name for tag in self.tagStack]).intersection( + self.PRESERVE_WHITESPACE_TAGS)): + if '\n' in currentData: + currentData = '\n' + else: + currentData = ' ' + self.currentData = [] + if self.parseOnlyThese and len(self.tagStack) <= 1 and \ + (not self.parseOnlyThese.text or \ + not self.parseOnlyThese.search(currentData)): + return + o = containerClass(currentData) + o.setup(self.currentTag, self.previous) + if self.previous: + self.previous.next = o + self.previous = o + self.currentTag.contents.append(o) + + + def _popToTag(self, name, inclusivePop=True): + """Pops the tag stack up to and including the most recent + instance of the given tag. If inclusivePop is false, pops the tag + stack up to but *not* including the most recent instqance of + the given tag.""" + #print "Popping to %s" % name + if name == self.ROOT_TAG_NAME: + return + + numPops = 0 + mostRecentTag = None + for i in range(len(self.tagStack)-1, 0, -1): + if name == self.tagStack[i].name: + numPops = len(self.tagStack)-i + break + if not inclusivePop: + numPops = numPops - 1 + + for i in range(0, numPops): + mostRecentTag = self.popTag() + return mostRecentTag + + def _smartPop(self, name): + + """We need to pop up to the previous tag of this type, unless + one of this tag's nesting reset triggers comes between this + tag and the previous tag of this type, OR unless this tag is a + generic nesting trigger and another generic nesting trigger + comes between this tag and the previous tag of this type. + + Examples: +

FooBar *

* should pop to 'p', not 'b'. +

FooBar *

* should pop to 'table', not 'p'. +

Foo

Bar *

* should pop to 'tr', not 'p'. + +

    • *
    • * should pop to 'ul', not the first 'li'. +
  • ** should pop to 'table', not the first 'tr' + tag should + implicitly close the previous tag within the same
    ** should pop to 'tr', not the first 'td' + """ + + nestingResetTriggers = self.NESTABLE_TAGS.get(name) + isNestable = nestingResetTriggers != None + isResetNesting = self.RESET_NESTING_TAGS.has_key(name) + popTo = None + inclusive = True + for i in range(len(self.tagStack)-1, 0, -1): + p = self.tagStack[i] + if (not p or p.name == name) and not isNestable: + #Non-nestable tags get popped to the top or to their + #last occurance. + popTo = name + break + if (nestingResetTriggers is not None + and p.name in nestingResetTriggers) \ + or (nestingResetTriggers is None and isResetNesting + and self.RESET_NESTING_TAGS.has_key(p.name)): + + #If we encounter one of the nesting reset triggers + #peculiar to this tag, or we encounter another tag + #that causes nesting to reset, pop up to but not + #including that tag. + popTo = p.name + inclusive = False + break + p = p.parent + if popTo: + self._popToTag(popTo, inclusive) + + def unknown_starttag(self, name, attrs, selfClosing=0): + #print "Start tag %s: %s" % (name, attrs) + if self.quoteStack: + #This is not a real tag. + #print "<%s> is not real!" % name + attrs = ''.join([' %s="%s"' % (x, y) for x, y in attrs]) + self.handle_data('<%s%s>' % (name, attrs)) + return + self.endData() + + if not self.isSelfClosingTag(name) and not selfClosing: + self._smartPop(name) + + if self.parseOnlyThese and len(self.tagStack) <= 1 \ + and (self.parseOnlyThese.text or not self.parseOnlyThese.searchTag(name, attrs)): + return + + tag = Tag(self, name, attrs, self.currentTag, self.previous) + if self.previous: + self.previous.next = tag + self.previous = tag + self.pushTag(tag) + if selfClosing or self.isSelfClosingTag(name): + self.popTag() + if name in self.QUOTE_TAGS: + #print "Beginning quote (%s)" % name + self.quoteStack.append(name) + self.literal = 1 + return tag + + def unknown_endtag(self, name): + #print "End tag %s" % name + if self.quoteStack and self.quoteStack[-1] != name: + #This is not a real end tag. + #print " is not real!" % name + self.handle_data('' % name) + return + self.endData() + self._popToTag(name) + if self.quoteStack and self.quoteStack[-1] == name: + self.quoteStack.pop() + self.literal = (len(self.quoteStack) > 0) + + def handle_data(self, data): + self.currentData.append(data) + + def _toStringSubclass(self, text, subclass): + """Adds a certain piece of text to the tree as a NavigableString + subclass.""" + self.endData() + self.handle_data(text) + self.endData(subclass) + + def handle_pi(self, text): + """Handle a processing instruction as a ProcessingInstruction + object, possibly one with a %SOUP-ENCODING% slot into which an + encoding will be plugged later.""" + if text[:3] == "xml": + text = u"xml version='1.0' encoding='%SOUP-ENCODING%'" + self._toStringSubclass(text, ProcessingInstruction) + + def handle_comment(self, text): + "Handle comments as Comment objects." + self._toStringSubclass(text, Comment) + + def handle_charref(self, ref): + "Handle character references as data." + if self.convertEntities: + data = unichr(int(ref)) + else: + data = '&#%s;' % ref + self.handle_data(data) + + def handle_entityref(self, ref): + """Handle entity references as data, possibly converting known + HTML and/or XML entity references to the corresponding Unicode + characters.""" + data = None + if self.convertHTMLEntities: + try: + data = unichr(name2codepoint[ref]) + except KeyError: + pass + + if not data and self.convertXMLEntities: + data = self.XML_ENTITIES_TO_SPECIAL_CHARS.get(ref) + + if not data and self.convertHTMLEntities and \ + not self.XML_ENTITIES_TO_SPECIAL_CHARS.get(ref): + # TODO: We've got a problem here. We're told this is + # an entity reference, but it's not an XML entity + # reference or an HTML entity reference. Nonetheless, + # the logical thing to do is to pass it through as an + # unrecognized entity reference. + # + # Except: when the input is "&carol;" this function + # will be called with input "carol". When the input is + # "AT&T", this function will be called with input + # "T". We have no way of knowing whether a semicolon + # was present originally, so we don't know whether + # this is an unknown entity or just a misplaced + # ampersand. + # + # The more common case is a misplaced ampersand, so I + # escape the ampersand and omit the trailing semicolon. + data = "&%s" % ref + if not data: + # This case is different from the one above, because we + # haven't already gone through a supposedly comprehensive + # mapping of entities to Unicode characters. We might not + # have gone through any mapping at all. So the chances are + # very high that this is a real entity, and not a + # misplaced ampersand. + data = "&%s;" % ref + self.handle_data(data) + + def handle_decl(self, data): + "Handle DOCTYPEs and the like as Declaration objects." + self._toStringSubclass(data, Declaration) + + def parse_declaration(self, i): + """Treat a bogus SGML declaration as raw data. Treat a CDATA + declaration as a CData object.""" + j = None + if self.rawdata[i:i+9] == '', i) + if k == -1: + k = len(self.rawdata) + data = self.rawdata[i+9:k] + j = k+3 + self._toStringSubclass(data, CData) + else: + try: + j = SGMLParser.parse_declaration(self, i) + except SGMLParseError: + toHandle = self.rawdata[i:] + self.handle_data(toHandle) + j = i + len(toHandle) + return j + +class BeautifulSoup(BeautifulStoneSoup): + + """This parser knows the following facts about HTML: + + * Some tags have no closing tag and should be interpreted as being + closed as soon as they are encountered. + + * The text inside some tags (ie. 'script') may contain tags which + are not really part of the document and which should be parsed + as text, not tags. If you want to parse the text as tags, you can + always fetch it and parse it explicitly. + + * Tag nesting rules: + + Most tags can't be nested at all. For instance, the occurance of + a

    tag should implicitly close the previous

    tag. + +

    Para1

    Para2 + should be transformed into: +

    Para1

    Para2 + + Some tags can be nested arbitrarily. For instance, the occurance + of a

    tag should _not_ implicitly close the previous +
    tag. + + Alice said:
    Bob said:
    Blah + should NOT be transformed into: + Alice said:
    Bob said:
    Blah + + Some tags can be nested, but the nesting is reset by the + interposition of other tags. For instance, a
    , + but not close a tag in another table. + +
    BlahBlah + should be transformed into: +
    BlahBlah + but, + Blah
    Blah + should NOT be transformed into + Blah
    Blah + + Differing assumptions about tag nesting rules are a major source + of problems with the BeautifulSoup class. If BeautifulSoup is not + treating as nestable a tag your page author treats as nestable, + try ICantBelieveItsBeautifulSoup, MinimalSoup, or + BeautifulStoneSoup before writing your own subclass.""" + + def __init__(self, *args, **kwargs): + if not kwargs.has_key('smartQuotesTo'): + kwargs['smartQuotesTo'] = self.HTML_ENTITIES + kwargs['isHTML'] = True + BeautifulStoneSoup.__init__(self, *args, **kwargs) + + SELF_CLOSING_TAGS = buildTagMap(None, + ('br' , 'hr', 'input', 'img', 'meta', + 'spacer', 'link', 'frame', 'base', 'col')) + + PRESERVE_WHITESPACE_TAGS = set(['pre', 'textarea']) + + QUOTE_TAGS = {'script' : None, 'textarea' : None} + + #According to the HTML standard, each of these inline tags can + #contain another tag of the same type. Furthermore, it's common + #to actually use these tags this way. + NESTABLE_INLINE_TAGS = ('span', 'font', 'q', 'object', 'bdo', 'sub', 'sup', + 'center') + + #According to the HTML standard, these block tags can contain + #another tag of the same type. Furthermore, it's common + #to actually use these tags this way. + NESTABLE_BLOCK_TAGS = ('blockquote', 'div', 'fieldset', 'ins', 'del') + + #Lists can contain other lists, but there are restrictions. + NESTABLE_LIST_TAGS = { 'ol' : [], + 'ul' : [], + 'li' : ['ul', 'ol'], + 'dl' : [], + 'dd' : ['dl'], + 'dt' : ['dl'] } + + #Tables can contain other tables, but there are restrictions. + NESTABLE_TABLE_TAGS = {'table' : [], + 'tr' : ['table', 'tbody', 'tfoot', 'thead'], + 'td' : ['tr'], + 'th' : ['tr'], + 'thead' : ['table'], + 'tbody' : ['table'], + 'tfoot' : ['table'], + } + + NON_NESTABLE_BLOCK_TAGS = ('address', 'form', 'p', 'pre') + + #If one of these tags is encountered, all tags up to the next tag of + #this type are popped. + RESET_NESTING_TAGS = buildTagMap(None, NESTABLE_BLOCK_TAGS, 'noscript', + NON_NESTABLE_BLOCK_TAGS, + NESTABLE_LIST_TAGS, + NESTABLE_TABLE_TAGS) + + NESTABLE_TAGS = buildTagMap([], NESTABLE_INLINE_TAGS, NESTABLE_BLOCK_TAGS, + NESTABLE_LIST_TAGS, NESTABLE_TABLE_TAGS) + + # Used to detect the charset in a META tag; see start_meta + CHARSET_RE = re.compile("((^|;)\s*charset=)([^;]*)", re.M) + + def start_meta(self, attrs): + """Beautiful Soup can detect a charset included in a META tag, + try to convert the document to that charset, and re-parse the + document from the beginning.""" + httpEquiv = None + contentType = None + contentTypeIndex = None + tagNeedsEncodingSubstitution = False + + for i in range(0, len(attrs)): + key, value = attrs[i] + key = key.lower() + if key == 'http-equiv': + httpEquiv = value + elif key == 'content': + contentType = value + contentTypeIndex = i + + if httpEquiv and contentType: # It's an interesting meta tag. + match = self.CHARSET_RE.search(contentType) + if match: + if (self.declaredHTMLEncoding is not None or + self.originalEncoding == self.fromEncoding): + # An HTML encoding was sniffed while converting + # the document to Unicode, or an HTML encoding was + # sniffed during a previous pass through the + # document, or an encoding was specified + # explicitly and it worked. Rewrite the meta tag. + def rewrite(match): + return match.group(1) + "%SOUP-ENCODING%" + newAttr = self.CHARSET_RE.sub(rewrite, contentType) + attrs[contentTypeIndex] = (attrs[contentTypeIndex][0], + newAttr) + tagNeedsEncodingSubstitution = True + else: + # This is our first pass through the document. + # Go through it again with the encoding information. + newCharset = match.group(3) + if newCharset and newCharset != self.originalEncoding: + self.declaredHTMLEncoding = newCharset + self._feed(self.declaredHTMLEncoding) + raise StopParsing + pass + tag = self.unknown_starttag("meta", attrs) + if tag and tagNeedsEncodingSubstitution: + tag.containsSubstitutions = True + +class StopParsing(Exception): + pass + +class ICantBelieveItsBeautifulSoup(BeautifulSoup): + + """The BeautifulSoup class is oriented towards skipping over + common HTML errors like unclosed tags. However, sometimes it makes + errors of its own. For instance, consider this fragment: + + FooBar + + This is perfectly valid (if bizarre) HTML. However, the + BeautifulSoup class will implicitly close the first b tag when it + encounters the second 'b'. It will think the author wrote + "FooBar", and didn't close the first 'b' tag, because + there's no real-world reason to bold something that's already + bold. When it encounters '' it will close two more 'b' + tags, for a grand total of three tags closed instead of two. This + can throw off the rest of your document structure. The same is + true of a number of other tags, listed below. + + It's much more common for someone to forget to close a 'b' tag + than to actually use nested 'b' tags, and the BeautifulSoup class + handles the common case. This class handles the not-co-common + case: where you can't believe someone wrote what they did, but + it's valid HTML and BeautifulSoup screwed up by assuming it + wouldn't be.""" + + I_CANT_BELIEVE_THEYRE_NESTABLE_INLINE_TAGS = \ + ('em', 'big', 'i', 'small', 'tt', 'abbr', 'acronym', 'strong', + 'cite', 'code', 'dfn', 'kbd', 'samp', 'strong', 'var', 'b', + 'big') + + I_CANT_BELIEVE_THEYRE_NESTABLE_BLOCK_TAGS = ('noscript',) + + NESTABLE_TAGS = buildTagMap([], BeautifulSoup.NESTABLE_TAGS, + I_CANT_BELIEVE_THEYRE_NESTABLE_BLOCK_TAGS, + I_CANT_BELIEVE_THEYRE_NESTABLE_INLINE_TAGS) + +class MinimalSoup(BeautifulSoup): + """The MinimalSoup class is for parsing HTML that contains + pathologically bad markup. It makes no assumptions about tag + nesting, but it does know which tags are self-closing, that + + +

    Error: {{e.status}}

    +

    Sorry, the requested URL {{repr(request.url)}} + caused an error:

    +
    {{e.body}}
    + %%if DEBUG and e.exception: +

    Exception:

    +
    {{repr(e.exception)}}
    + %%end + %%if DEBUG and e.traceback: +

    Traceback:

    +
    {{e.traceback}}
    + %%end + + +%%except ImportError: + ImportError: Could not generate the error page. Please add bottle to + the import path. +%%end +""" % __name__ + +#: A thread-safe instance of :class:`LocalRequest`. If accessed from within a +#: request callback, this instance always refers to the *current* request +#: (even on a multithreaded server). +request = LocalRequest() + +#: A thread-safe instance of :class:`LocalResponse`. It is used to change the +#: HTTP response for the *current* request. +response = LocalResponse() + +#: A thread-safe namespace. Not used by Bottle. +local = threading.local() + +# Initialize app stack (create first empty Bottle app) +# BC: 0.6.4 and needed for run() +app = default_app = AppStack() +app.push() + +#: A virtual package that redirects import statements. +#: Example: ``import bottle.ext.sqlite`` actually imports `bottle_sqlite`. +ext = _ImportRedirect('bottle.ext' if __name__ == '__main__' else __name__+".ext", 'bottle_%s').module + +if __name__ == '__main__': + opt, args, parser = _cmd_options, _cmd_args, _cmd_parser + if opt.version: + _stdout('Bottle %s\n'%__version__) + sys.exit(0) + if not args: + parser.print_help() + _stderr('\nError: No application specified.\n') + sys.exit(1) + + sys.path.insert(0, '.') + sys.modules.setdefault('bottle', sys.modules['__main__']) + + host, port = (opt.bind or 'localhost'), 8080 + if ':' in host and host.rfind(']') < host.rfind(':'): + host, port = host.rsplit(':', 1) + host = host.strip('[]') + + run(args[0], host=host, port=int(port), server=opt.server, + reloader=opt.reload, plugins=opt.plugin, debug=opt.debug) + + + + +# THE END diff --git a/tools/utils/contrib/colorama/__init__.py b/tools/utils/contrib/colorama/__init__.py new file mode 100755 index 0000000000..f4d9ce2108 --- /dev/null +++ b/tools/utils/contrib/colorama/__init__.py @@ -0,0 +1,7 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +from .initialise import init, deinit, reinit, colorama_text +from .ansi import Fore, Back, Style, Cursor +from .ansitowin32 import AnsiToWin32 + +__version__ = '0.3.9' + diff --git a/tools/utils/contrib/colorama/ansi.py b/tools/utils/contrib/colorama/ansi.py new file mode 100755 index 0000000000..78776588db --- /dev/null +++ b/tools/utils/contrib/colorama/ansi.py @@ -0,0 +1,102 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +''' +This module generates ANSI character codes to printing colors to terminals. +See: http://en.wikipedia.org/wiki/ANSI_escape_code +''' + +CSI = '\033[' +OSC = '\033]' +BEL = '\007' + + +def code_to_chars(code): + return CSI + str(code) + 'm' + +def set_title(title): + return OSC + '2;' + title + BEL + +def clear_screen(mode=2): + return CSI + str(mode) + 'J' + +def clear_line(mode=2): + return CSI + str(mode) + 'K' + + +class AnsiCodes(object): + def __init__(self): + # the subclasses declare class attributes which are numbers. + # Upon instantiation we define instance attributes, which are the same + # as the class attributes but wrapped with the ANSI escape sequence + for name in dir(self): + if not name.startswith('_'): + value = getattr(self, name) + setattr(self, name, code_to_chars(value)) + + +class AnsiCursor(object): + def UP(self, n=1): + return CSI + str(n) + 'A' + def DOWN(self, n=1): + return CSI + str(n) + 'B' + def FORWARD(self, n=1): + return CSI + str(n) + 'C' + def BACK(self, n=1): + return CSI + str(n) + 'D' + def POS(self, x=1, y=1): + return CSI + str(y) + ';' + str(x) + 'H' + + +class AnsiFore(AnsiCodes): + BLACK = 30 + RED = 31 + GREEN = 32 + YELLOW = 33 + BLUE = 34 + MAGENTA = 35 + CYAN = 36 + WHITE = 37 + RESET = 39 + + # These are fairly well supported, but not part of the standard. + LIGHTBLACK_EX = 90 + LIGHTRED_EX = 91 + LIGHTGREEN_EX = 92 + LIGHTYELLOW_EX = 93 + LIGHTBLUE_EX = 94 + LIGHTMAGENTA_EX = 95 + LIGHTCYAN_EX = 96 + LIGHTWHITE_EX = 97 + + +class AnsiBack(AnsiCodes): + BLACK = 40 + RED = 41 + GREEN = 42 + YELLOW = 43 + BLUE = 44 + MAGENTA = 45 + CYAN = 46 + WHITE = 47 + RESET = 49 + + # These are fairly well supported, but not part of the standard. + LIGHTBLACK_EX = 100 + LIGHTRED_EX = 101 + LIGHTGREEN_EX = 102 + LIGHTYELLOW_EX = 103 + LIGHTBLUE_EX = 104 + LIGHTMAGENTA_EX = 105 + LIGHTCYAN_EX = 106 + LIGHTWHITE_EX = 107 + + +class AnsiStyle(AnsiCodes): + BRIGHT = 1 + DIM = 2 + NORMAL = 22 + RESET_ALL = 0 + +Fore = AnsiFore() +Back = AnsiBack() +Style = AnsiStyle() +Cursor = AnsiCursor() diff --git a/tools/utils/contrib/colorama/ansitowin32.py b/tools/utils/contrib/colorama/ansitowin32.py new file mode 100755 index 0000000000..1d6e6059c7 --- /dev/null +++ b/tools/utils/contrib/colorama/ansitowin32.py @@ -0,0 +1,236 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +import re +import sys +import os + +from .ansi import AnsiFore, AnsiBack, AnsiStyle, Style +from .winterm import WinTerm, WinColor, WinStyle +from .win32 import windll, winapi_test + + +winterm = None +if windll is not None: + winterm = WinTerm() + + +def is_stream_closed(stream): + return not hasattr(stream, 'closed') or stream.closed + + +def is_a_tty(stream): + return hasattr(stream, 'isatty') and stream.isatty() + + +class StreamWrapper(object): + ''' + Wraps a stream (such as stdout), acting as a transparent proxy for all + attribute access apart from method 'write()', which is delegated to our + Converter instance. + ''' + def __init__(self, wrapped, converter): + # double-underscore everything to prevent clashes with names of + # attributes on the wrapped stream object. + self.__wrapped = wrapped + self.__convertor = converter + + def __getattr__(self, name): + return getattr(self.__wrapped, name) + + def write(self, text): + self.__convertor.write(text) + + +class AnsiToWin32(object): + ''' + Implements a 'write()' method which, on Windows, will strip ANSI character + sequences from the text, and if outputting to a tty, will convert them into + win32 function calls. + ''' + ANSI_CSI_RE = re.compile('\001?\033\\[((?:\\d|;)*)([a-zA-Z])\002?') # Control Sequence Introducer + ANSI_OSC_RE = re.compile('\001?\033\\]((?:.|;)*?)(\x07)\002?') # Operating System Command + + def __init__(self, wrapped, convert=None, strip=None, autoreset=False): + # The wrapped stream (normally sys.stdout or sys.stderr) + self.wrapped = wrapped + + # should we reset colors to defaults after every .write() + self.autoreset = autoreset + + # create the proxy wrapping our output stream + self.stream = StreamWrapper(wrapped, self) + + on_windows = os.name == 'nt' + # We test if the WinAPI works, because even if we are on Windows + # we may be using a terminal that doesn't support the WinAPI + # (e.g. Cygwin Terminal). In this case it's up to the terminal + # to support the ANSI codes. + conversion_supported = on_windows and winapi_test() + + # should we strip ANSI sequences from our output? + if strip is None: + strip = conversion_supported or (not is_stream_closed(wrapped) and not is_a_tty(wrapped)) + self.strip = strip + + # should we should convert ANSI sequences into win32 calls? + if convert is None: + convert = conversion_supported and not is_stream_closed(wrapped) and is_a_tty(wrapped) + self.convert = convert + + # dict of ansi codes to win32 functions and parameters + self.win32_calls = self.get_win32_calls() + + # are we wrapping stderr? + self.on_stderr = self.wrapped is sys.stderr + + def should_wrap(self): + ''' + True if this class is actually needed. If false, then the output + stream will not be affected, nor will win32 calls be issued, so + wrapping stdout is not actually required. This will generally be + False on non-Windows platforms, unless optional functionality like + autoreset has been requested using kwargs to init() + ''' + return self.convert or self.strip or self.autoreset + + def get_win32_calls(self): + if self.convert and winterm: + return { + AnsiStyle.RESET_ALL: (winterm.reset_all, ), + AnsiStyle.BRIGHT: (winterm.style, WinStyle.BRIGHT), + AnsiStyle.DIM: (winterm.style, WinStyle.NORMAL), + AnsiStyle.NORMAL: (winterm.style, WinStyle.NORMAL), + AnsiFore.BLACK: (winterm.fore, WinColor.BLACK), + AnsiFore.RED: (winterm.fore, WinColor.RED), + AnsiFore.GREEN: (winterm.fore, WinColor.GREEN), + AnsiFore.YELLOW: (winterm.fore, WinColor.YELLOW), + AnsiFore.BLUE: (winterm.fore, WinColor.BLUE), + AnsiFore.MAGENTA: (winterm.fore, WinColor.MAGENTA), + AnsiFore.CYAN: (winterm.fore, WinColor.CYAN), + AnsiFore.WHITE: (winterm.fore, WinColor.GREY), + AnsiFore.RESET: (winterm.fore, ), + AnsiFore.LIGHTBLACK_EX: (winterm.fore, WinColor.BLACK, True), + AnsiFore.LIGHTRED_EX: (winterm.fore, WinColor.RED, True), + AnsiFore.LIGHTGREEN_EX: (winterm.fore, WinColor.GREEN, True), + AnsiFore.LIGHTYELLOW_EX: (winterm.fore, WinColor.YELLOW, True), + AnsiFore.LIGHTBLUE_EX: (winterm.fore, WinColor.BLUE, True), + AnsiFore.LIGHTMAGENTA_EX: (winterm.fore, WinColor.MAGENTA, True), + AnsiFore.LIGHTCYAN_EX: (winterm.fore, WinColor.CYAN, True), + AnsiFore.LIGHTWHITE_EX: (winterm.fore, WinColor.GREY, True), + AnsiBack.BLACK: (winterm.back, WinColor.BLACK), + AnsiBack.RED: (winterm.back, WinColor.RED), + AnsiBack.GREEN: (winterm.back, WinColor.GREEN), + AnsiBack.YELLOW: (winterm.back, WinColor.YELLOW), + AnsiBack.BLUE: (winterm.back, WinColor.BLUE), + AnsiBack.MAGENTA: (winterm.back, WinColor.MAGENTA), + AnsiBack.CYAN: (winterm.back, WinColor.CYAN), + AnsiBack.WHITE: (winterm.back, WinColor.GREY), + AnsiBack.RESET: (winterm.back, ), + AnsiBack.LIGHTBLACK_EX: (winterm.back, WinColor.BLACK, True), + AnsiBack.LIGHTRED_EX: (winterm.back, WinColor.RED, True), + AnsiBack.LIGHTGREEN_EX: (winterm.back, WinColor.GREEN, True), + AnsiBack.LIGHTYELLOW_EX: (winterm.back, WinColor.YELLOW, True), + AnsiBack.LIGHTBLUE_EX: (winterm.back, WinColor.BLUE, True), + AnsiBack.LIGHTMAGENTA_EX: (winterm.back, WinColor.MAGENTA, True), + AnsiBack.LIGHTCYAN_EX: (winterm.back, WinColor.CYAN, True), + AnsiBack.LIGHTWHITE_EX: (winterm.back, WinColor.GREY, True), + } + return dict() + + def write(self, text): + if self.strip or self.convert: + self.write_and_convert(text) + else: + self.wrapped.write(text) + self.wrapped.flush() + if self.autoreset: + self.reset_all() + + + def reset_all(self): + if self.convert: + self.call_win32('m', (0,)) + elif not self.strip and not is_stream_closed(self.wrapped): + self.wrapped.write(Style.RESET_ALL) + + + def write_and_convert(self, text): + ''' + Write the given text to our wrapped stream, stripping any ANSI + sequences from the text, and optionally converting them into win32 + calls. + ''' + cursor = 0 + text = self.convert_osc(text) + for match in self.ANSI_CSI_RE.finditer(text): + start, end = match.span() + self.write_plain_text(text, cursor, start) + self.convert_ansi(*match.groups()) + cursor = end + self.write_plain_text(text, cursor, len(text)) + + + def write_plain_text(self, text, start, end): + if start < end: + self.wrapped.write(text[start:end]) + self.wrapped.flush() + + + def convert_ansi(self, paramstring, command): + if self.convert: + params = self.extract_params(command, paramstring) + self.call_win32(command, params) + + + def extract_params(self, command, paramstring): + if command in 'Hf': + params = tuple(int(p) if len(p) != 0 else 1 for p in paramstring.split(';')) + while len(params) < 2: + # defaults: + params = params + (1,) + else: + params = tuple(int(p) for p in paramstring.split(';') if len(p) != 0) + if len(params) == 0: + # defaults: + if command in 'JKm': + params = (0,) + elif command in 'ABCD': + params = (1,) + + return params + + + def call_win32(self, command, params): + if command == 'm': + for param in params: + if param in self.win32_calls: + func_args = self.win32_calls[param] + func = func_args[0] + args = func_args[1:] + kwargs = dict(on_stderr=self.on_stderr) + func(*args, **kwargs) + elif command in 'J': + winterm.erase_screen(params[0], on_stderr=self.on_stderr) + elif command in 'K': + winterm.erase_line(params[0], on_stderr=self.on_stderr) + elif command in 'Hf': # cursor position - absolute + winterm.set_cursor_position(params, on_stderr=self.on_stderr) + elif command in 'ABCD': # cursor position - relative + n = params[0] + # A - up, B - down, C - forward, D - back + x, y = {'A': (0, -n), 'B': (0, n), 'C': (n, 0), 'D': (-n, 0)}[command] + winterm.cursor_adjust(x, y, on_stderr=self.on_stderr) + + + def convert_osc(self, text): + for match in self.ANSI_OSC_RE.finditer(text): + start, end = match.span() + text = text[:start] + text[end:] + paramstring, command = match.groups() + if command in '\x07': # \x07 = BEL + params = paramstring.split(";") + # 0 - change title and icon (we will only change title) + # 1 - change icon (we don't support this) + # 2 - change title + if params[0] in '02': + winterm.set_title(params[1]) + return text diff --git a/tools/utils/contrib/colorama/initialise.py b/tools/utils/contrib/colorama/initialise.py new file mode 100755 index 0000000000..834962a35f --- /dev/null +++ b/tools/utils/contrib/colorama/initialise.py @@ -0,0 +1,82 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +import atexit +import contextlib +import sys + +from .ansitowin32 import AnsiToWin32 + + +orig_stdout = None +orig_stderr = None + +wrapped_stdout = None +wrapped_stderr = None + +atexit_done = False + + +def reset_all(): + if AnsiToWin32 is not None: # Issue #74: objects might become None at exit + AnsiToWin32(orig_stdout).reset_all() + + +def init(autoreset=False, convert=None, strip=None, wrap=True): + + if not wrap and any([autoreset, convert, strip]): + raise ValueError('wrap=False conflicts with any other arg=True') + + global wrapped_stdout, wrapped_stderr + global orig_stdout, orig_stderr + + orig_stdout = sys.stdout + orig_stderr = sys.stderr + + if sys.stdout is None: + wrapped_stdout = None + else: + sys.stdout = wrapped_stdout = \ + wrap_stream(orig_stdout, convert, strip, autoreset, wrap) + if sys.stderr is None: + wrapped_stderr = None + else: + sys.stderr = wrapped_stderr = \ + wrap_stream(orig_stderr, convert, strip, autoreset, wrap) + + global atexit_done + if not atexit_done: + atexit.register(reset_all) + atexit_done = True + + +def deinit(): + if orig_stdout is not None: + sys.stdout = orig_stdout + if orig_stderr is not None: + sys.stderr = orig_stderr + + +@contextlib.contextmanager +def colorama_text(*args, **kwargs): + init(*args, **kwargs) + try: + yield + finally: + deinit() + + +def reinit(): + if wrapped_stdout is not None: + sys.stdout = wrapped_stdout + if wrapped_stderr is not None: + sys.stderr = wrapped_stderr + + +def wrap_stream(stream, convert, strip, autoreset, wrap): + if wrap: + wrapper = AnsiToWin32(stream, + convert=convert, strip=strip, autoreset=autoreset) + if wrapper.should_wrap(): + stream = wrapper.stream + return stream + + diff --git a/tools/utils/contrib/colorama/win32.py b/tools/utils/contrib/colorama/win32.py new file mode 100755 index 0000000000..8262e350a6 --- /dev/null +++ b/tools/utils/contrib/colorama/win32.py @@ -0,0 +1,156 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. + +# from winbase.h +STDOUT = -11 +STDERR = -12 + +try: + import ctypes + from ctypes import LibraryLoader + windll = LibraryLoader(ctypes.WinDLL) + from ctypes import wintypes +except (AttributeError, ImportError): + windll = None + SetConsoleTextAttribute = lambda *_: None + winapi_test = lambda *_: None +else: + from ctypes import byref, Structure, c_char, POINTER + + COORD = wintypes._COORD + + class CONSOLE_SCREEN_BUFFER_INFO(Structure): + """struct in wincon.h.""" + _fields_ = [ + ("dwSize", COORD), + ("dwCursorPosition", COORD), + ("wAttributes", wintypes.WORD), + ("srWindow", wintypes.SMALL_RECT), + ("dwMaximumWindowSize", COORD), + ] + def __str__(self): + return '(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)' % ( + self.dwSize.Y, self.dwSize.X + , self.dwCursorPosition.Y, self.dwCursorPosition.X + , self.wAttributes + , self.srWindow.Top, self.srWindow.Left, self.srWindow.Bottom, self.srWindow.Right + , self.dwMaximumWindowSize.Y, self.dwMaximumWindowSize.X + ) + + _GetStdHandle = windll.kernel32.GetStdHandle + _GetStdHandle.argtypes = [ + wintypes.DWORD, + ] + _GetStdHandle.restype = wintypes.HANDLE + + _GetConsoleScreenBufferInfo = windll.kernel32.GetConsoleScreenBufferInfo + _GetConsoleScreenBufferInfo.argtypes = [ + wintypes.HANDLE, + POINTER(CONSOLE_SCREEN_BUFFER_INFO), + ] + _GetConsoleScreenBufferInfo.restype = wintypes.BOOL + + _SetConsoleTextAttribute = windll.kernel32.SetConsoleTextAttribute + _SetConsoleTextAttribute.argtypes = [ + wintypes.HANDLE, + wintypes.WORD, + ] + _SetConsoleTextAttribute.restype = wintypes.BOOL + + _SetConsoleCursorPosition = windll.kernel32.SetConsoleCursorPosition + _SetConsoleCursorPosition.argtypes = [ + wintypes.HANDLE, + COORD, + ] + _SetConsoleCursorPosition.restype = wintypes.BOOL + + _FillConsoleOutputCharacterA = windll.kernel32.FillConsoleOutputCharacterA + _FillConsoleOutputCharacterA.argtypes = [ + wintypes.HANDLE, + c_char, + wintypes.DWORD, + COORD, + POINTER(wintypes.DWORD), + ] + _FillConsoleOutputCharacterA.restype = wintypes.BOOL + + _FillConsoleOutputAttribute = windll.kernel32.FillConsoleOutputAttribute + _FillConsoleOutputAttribute.argtypes = [ + wintypes.HANDLE, + wintypes.WORD, + wintypes.DWORD, + COORD, + POINTER(wintypes.DWORD), + ] + _FillConsoleOutputAttribute.restype = wintypes.BOOL + + _SetConsoleTitleW = windll.kernel32.SetConsoleTitleW + _SetConsoleTitleW.argtypes = [ + wintypes.LPCWSTR + ] + _SetConsoleTitleW.restype = wintypes.BOOL + + handles = { + STDOUT: _GetStdHandle(STDOUT), + STDERR: _GetStdHandle(STDERR), + } + + def _winapi_test(handle): + csbi = CONSOLE_SCREEN_BUFFER_INFO() + success = _GetConsoleScreenBufferInfo( + handle, byref(csbi)) + return bool(success) + + def winapi_test(): + return any(_winapi_test(h) for h in handles.values()) + + def GetConsoleScreenBufferInfo(stream_id=STDOUT): + handle = handles[stream_id] + csbi = CONSOLE_SCREEN_BUFFER_INFO() + success = _GetConsoleScreenBufferInfo( + handle, byref(csbi)) + return csbi + + def SetConsoleTextAttribute(stream_id, attrs): + handle = handles[stream_id] + return _SetConsoleTextAttribute(handle, attrs) + + def SetConsoleCursorPosition(stream_id, position, adjust=True): + position = COORD(*position) + # If the position is out of range, do nothing. + if position.Y <= 0 or position.X <= 0: + return + # Adjust for Windows' SetConsoleCursorPosition: + # 1. being 0-based, while ANSI is 1-based. + # 2. expecting (x,y), while ANSI uses (y,x). + adjusted_position = COORD(position.Y - 1, position.X - 1) + if adjust: + # Adjust for viewport's scroll position + sr = GetConsoleScreenBufferInfo(STDOUT).srWindow + adjusted_position.Y += sr.Top + adjusted_position.X += sr.Left + # Resume normal processing + handle = handles[stream_id] + return _SetConsoleCursorPosition(handle, adjusted_position) + + def FillConsoleOutputCharacter(stream_id, char, length, start): + handle = handles[stream_id] + char = c_char(char.encode()) + length = wintypes.DWORD(length) + num_written = wintypes.DWORD(0) + # Note that this is hard-coded for ANSI (vs wide) bytes. + success = _FillConsoleOutputCharacterA( + handle, char, length, start, byref(num_written)) + return num_written.value + + def FillConsoleOutputAttribute(stream_id, attr, length, start): + ''' FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten )''' + handle = handles[stream_id] + attribute = wintypes.WORD(attr) + length = wintypes.DWORD(length) + num_written = wintypes.DWORD(0) + # Note that this is hard-coded for ANSI (vs wide) bytes. + return _FillConsoleOutputAttribute( + handle, attribute, length, start, byref(num_written)) + + def SetConsoleTitle(title): + return _SetConsoleTitleW(title) diff --git a/tools/utils/contrib/colorama/winterm.py b/tools/utils/contrib/colorama/winterm.py new file mode 100755 index 0000000000..60309d3c07 --- /dev/null +++ b/tools/utils/contrib/colorama/winterm.py @@ -0,0 +1,162 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +from . import win32 + + +# from wincon.h +class WinColor(object): + BLACK = 0 + BLUE = 1 + GREEN = 2 + CYAN = 3 + RED = 4 + MAGENTA = 5 + YELLOW = 6 + GREY = 7 + +# from wincon.h +class WinStyle(object): + NORMAL = 0x00 # dim text, dim background + BRIGHT = 0x08 # bright text, dim background + BRIGHT_BACKGROUND = 0x80 # dim text, bright background + +class WinTerm(object): + + def __init__(self): + self._default = win32.GetConsoleScreenBufferInfo(win32.STDOUT).wAttributes + self.set_attrs(self._default) + self._default_fore = self._fore + self._default_back = self._back + self._default_style = self._style + # In order to emulate LIGHT_EX in windows, we borrow the BRIGHT style. + # So that LIGHT_EX colors and BRIGHT style do not clobber each other, + # we track them separately, since LIGHT_EX is overwritten by Fore/Back + # and BRIGHT is overwritten by Style codes. + self._light = 0 + + def get_attrs(self): + return self._fore + self._back * 16 + (self._style | self._light) + + def set_attrs(self, value): + self._fore = value & 7 + self._back = (value >> 4) & 7 + self._style = value & (WinStyle.BRIGHT | WinStyle.BRIGHT_BACKGROUND) + + def reset_all(self, on_stderr=None): + self.set_attrs(self._default) + self.set_console(attrs=self._default) + + def fore(self, fore=None, light=False, on_stderr=False): + if fore is None: + fore = self._default_fore + self._fore = fore + # Emulate LIGHT_EX with BRIGHT Style + if light: + self._light |= WinStyle.BRIGHT + else: + self._light &= ~WinStyle.BRIGHT + self.set_console(on_stderr=on_stderr) + + def back(self, back=None, light=False, on_stderr=False): + if back is None: + back = self._default_back + self._back = back + # Emulate LIGHT_EX with BRIGHT_BACKGROUND Style + if light: + self._light |= WinStyle.BRIGHT_BACKGROUND + else: + self._light &= ~WinStyle.BRIGHT_BACKGROUND + self.set_console(on_stderr=on_stderr) + + def style(self, style=None, on_stderr=False): + if style is None: + style = self._default_style + self._style = style + self.set_console(on_stderr=on_stderr) + + def set_console(self, attrs=None, on_stderr=False): + if attrs is None: + attrs = self.get_attrs() + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + win32.SetConsoleTextAttribute(handle, attrs) + + def get_position(self, handle): + position = win32.GetConsoleScreenBufferInfo(handle).dwCursorPosition + # Because Windows coordinates are 0-based, + # and win32.SetConsoleCursorPosition expects 1-based. + position.X += 1 + position.Y += 1 + return position + + def set_cursor_position(self, position=None, on_stderr=False): + if position is None: + # I'm not currently tracking the position, so there is no default. + # position = self.get_position() + return + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + win32.SetConsoleCursorPosition(handle, position) + + def cursor_adjust(self, x, y, on_stderr=False): + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + position = self.get_position(handle) + adjusted_position = (position.Y + y, position.X + x) + win32.SetConsoleCursorPosition(handle, adjusted_position, adjust=False) + + def erase_screen(self, mode=0, on_stderr=False): + # 0 should clear from the cursor to the end of the screen. + # 1 should clear from the cursor to the beginning of the screen. + # 2 should clear the entire screen, and move cursor to (1,1) + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + csbi = win32.GetConsoleScreenBufferInfo(handle) + # get the number of character cells in the current buffer + cells_in_screen = csbi.dwSize.X * csbi.dwSize.Y + # get number of character cells before current cursor position + cells_before_cursor = csbi.dwSize.X * csbi.dwCursorPosition.Y + csbi.dwCursorPosition.X + if mode == 0: + from_coord = csbi.dwCursorPosition + cells_to_erase = cells_in_screen - cells_before_cursor + if mode == 1: + from_coord = win32.COORD(0, 0) + cells_to_erase = cells_before_cursor + elif mode == 2: + from_coord = win32.COORD(0, 0) + cells_to_erase = cells_in_screen + # fill the entire screen with blanks + win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord) + # now set the buffer's attributes accordingly + win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord) + if mode == 2: + # put the cursor where needed + win32.SetConsoleCursorPosition(handle, (1, 1)) + + def erase_line(self, mode=0, on_stderr=False): + # 0 should clear from the cursor to the end of the line. + # 1 should clear from the cursor to the beginning of the line. + # 2 should clear the entire line. + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + csbi = win32.GetConsoleScreenBufferInfo(handle) + if mode == 0: + from_coord = csbi.dwCursorPosition + cells_to_erase = csbi.dwSize.X - csbi.dwCursorPosition.X + if mode == 1: + from_coord = win32.COORD(0, csbi.dwCursorPosition.Y) + cells_to_erase = csbi.dwCursorPosition.X + elif mode == 2: + from_coord = win32.COORD(0, csbi.dwCursorPosition.Y) + cells_to_erase = csbi.dwSize.X + # fill the entire screen with blanks + win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord) + # now set the buffer's attributes accordingly + win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord) + + def set_title(self, title): + win32.SetConsoleTitle(title) diff --git a/tools/utils/contrib/elftools/__init__.py b/tools/utils/contrib/elftools/__init__.py new file mode 100755 index 0000000000..4e2393f45f --- /dev/null +++ b/tools/utils/contrib/elftools/__init__.py @@ -0,0 +1,7 @@ +#------------------------------------------------------------------------------- +# elftools +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +__version__ = '0.23' diff --git a/tools/utils/contrib/elftools/common/__init__.py b/tools/utils/contrib/elftools/common/__init__.py new file mode 100755 index 0000000000..e69de29bb2 diff --git a/tools/utils/contrib/elftools/common/construct_utils.py b/tools/utils/contrib/elftools/common/construct_utils.py new file mode 100755 index 0000000000..53caa978fd --- /dev/null +++ b/tools/utils/contrib/elftools/common/construct_utils.py @@ -0,0 +1,45 @@ +#------------------------------------------------------------------------------- +# elftools: common/construct_utils.py +# +# Some complementary construct utilities +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +from ..construct import Subconstruct, ConstructError, ArrayError + + +class RepeatUntilExcluding(Subconstruct): + """ A version of construct's RepeatUntil that doesn't include the last + element (which casued the repeat to exit) in the return value. + + Only parsing is currently implemented. + + P.S. removed some code duplication + """ + __slots__ = ["predicate"] + def __init__(self, predicate, subcon): + Subconstruct.__init__(self, subcon) + self.predicate = predicate + self._clear_flag(self.FLAG_COPY_CONTEXT) + self._set_flag(self.FLAG_DYNAMIC) + def _parse(self, stream, context): + obj = [] + try: + context_for_subcon = context + if self.subcon.conflags & self.FLAG_COPY_CONTEXT: + context_for_subcon = context.__copy__() + + while True: + subobj = self.subcon._parse(stream, context_for_subcon) + if self.predicate(subobj, context): + break + obj.append(subobj) + except ConstructError as ex: + raise ArrayError("missing terminator", ex) + return obj + def _build(self, obj, stream, context): + raise NotImplementedError('no building') + def _sizeof(self, context): + raise SizeofError("can't calculate size") + diff --git a/tools/utils/contrib/elftools/common/exceptions.py b/tools/utils/contrib/elftools/common/exceptions.py new file mode 100755 index 0000000000..26f1ba09f3 --- /dev/null +++ b/tools/utils/contrib/elftools/common/exceptions.py @@ -0,0 +1,20 @@ +#------------------------------------------------------------------------------- +# elftools: common/exceptions.py +# +# Exception classes for elftools +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +class ELFError(Exception): + pass + +class ELFRelocationError(ELFError): + pass + +class ELFParseError(ELFError): + pass + +class DWARFError(Exception): + pass + diff --git a/tools/utils/contrib/elftools/common/py3compat.py b/tools/utils/contrib/elftools/common/py3compat.py new file mode 100755 index 0000000000..4878bf31c5 --- /dev/null +++ b/tools/utils/contrib/elftools/common/py3compat.py @@ -0,0 +1,59 @@ +#------------------------------------------------------------------------------- +# elftools: common/py3compat.py +# +# Python 3 compatibility code +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +import sys +PY3 = sys.version_info[0] == 3 + + +if PY3: + import io + StringIO = io.StringIO + BytesIO = io.BytesIO + + _iterkeys = "keys" + _iteritems = "items" + _itervalues = "values" + + def bytes2str(b): return b.decode('latin-1') + def str2bytes(s): return s.encode('latin-1') + def int2byte(i):return bytes((i,)) + def byte2int(b): return b + + ifilter = filter + + maxint = sys.maxsize +else: + import cStringIO + StringIO = BytesIO = cStringIO.StringIO + + _iterkeys = "iterkeys" + _iteritems = "iteritems" + _itervalues = "itervalues" + + def bytes2str(b): return b + def str2bytes(s): return s + int2byte = chr + byte2int = ord + + from itertools import ifilter + + maxint = sys.maxint + + +def iterkeys(d): + """Return an iterator over the keys of a dictionary.""" + return getattr(d, _iterkeys)() + +def itervalues(d): + """Return an iterator over the values of a dictionary.""" + return getattr(d, _itervalues)() + +def iteritems(d): + """Return an iterator over the items of a dictionary.""" + return getattr(d, _iteritems)() + diff --git a/tools/utils/contrib/elftools/common/utils.py b/tools/utils/contrib/elftools/common/utils.py new file mode 100755 index 0000000000..d8acefab2c --- /dev/null +++ b/tools/utils/contrib/elftools/common/utils.py @@ -0,0 +1,101 @@ +#------------------------------------------------------------------------------- +# elftools: common/utils.py +# +# Miscellaneous utilities for elftools +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +from contextlib import contextmanager +from .exceptions import ELFParseError, ELFError, DWARFError +from .py3compat import int2byte +from ..construct import ConstructError + + +def bytelist2string(bytelist): + """ Convert a list of byte values (e.g. [0x10 0x20 0x00]) to a bytes object + (e.g. b'\x10\x20\x00'). + """ + return b''.join(int2byte(b) for b in bytelist) + + +def struct_parse(struct, stream, stream_pos=None): + """ Convenience function for using the given struct to parse a stream. + If stream_pos is provided, the stream is seeked to this position before + the parsing is done. Otherwise, the current position of the stream is + used. + Wraps the error thrown by construct with ELFParseError. + """ + try: + if stream_pos is not None: + stream.seek(stream_pos) + return struct.parse_stream(stream) + except ConstructError as e: + raise ELFParseError(str(e)) + + +def parse_cstring_from_stream(stream, stream_pos=None): + """ Parse a C-string from the given stream. The string is returned without + the terminating \x00 byte. If the terminating byte wasn't found, None + is returned (the stream is exhausted). + If stream_pos is provided, the stream is seeked to this position before + the parsing is done. Otherwise, the current position of the stream is + used. + Note: a bytes object is returned here, because this is what's read from + the binary file. + """ + if stream_pos is not None: + stream.seek(stream_pos) + CHUNKSIZE = 64 + chunks = [] + found = False + while True: + chunk = stream.read(CHUNKSIZE) + end_index = chunk.find(b'\x00') + if end_index >= 0: + chunks.append(chunk[:end_index]) + found = True + break + else: + chunks.append(chunk) + if len(chunk) < CHUNKSIZE: + break + return b''.join(chunks) if found else None + + +def elf_assert(cond, msg=''): + """ Assert that cond is True, otherwise raise ELFError(msg) + """ + _assert_with_exception(cond, msg, ELFError) + + +def dwarf_assert(cond, msg=''): + """ Assert that cond is True, otherwise raise DWARFError(msg) + """ + _assert_with_exception(cond, msg, DWARFError) + + +@contextmanager +def preserve_stream_pos(stream): + """ Usage: + # stream has some position FOO (return value of stream.tell()) + with preserve_stream_pos(stream): + # do stuff that manipulates the stream + # stream still has position FOO + """ + saved_pos = stream.tell() + yield + stream.seek(saved_pos) + + +def roundup(num, bits): + """ Round up a number to nearest multiple of 2^bits. The result is a number + where the least significant bits passed in bits are 0. + """ + return (num - 1 | (1 << bits) - 1) + 1 + +#------------------------- PRIVATE ------------------------- + +def _assert_with_exception(cond, msg, exception_type): + if not cond: + raise exception_type(msg) diff --git a/tools/utils/contrib/elftools/construct/LICENSE b/tools/utils/contrib/elftools/construct/LICENSE new file mode 100755 index 0000000000..6529f04a89 --- /dev/null +++ b/tools/utils/contrib/elftools/construct/LICENSE @@ -0,0 +1,19 @@ +Copyright (C) 2009 Tomer Filiba, 2010-2011 Corbin Simpson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/tools/utils/contrib/elftools/construct/README b/tools/utils/contrib/elftools/construct/README new file mode 100755 index 0000000000..7f9e1418c7 --- /dev/null +++ b/tools/utils/contrib/elftools/construct/README @@ -0,0 +1,10 @@ +construct is a Python library for declarative parsing and building of binary +data. This is my fork of construct 2, with some modifications for Python 3 +and bug fixes. The construct website is http://construct.readthedocs.org + +pyelftools carries construct around because construct has been abandoned for +a long time and didn't get bugfixes; it also didn't work with Python 3. + +LICENSE is the original license. + + diff --git a/tools/utils/contrib/elftools/construct/__init__.py b/tools/utils/contrib/elftools/construct/__init__.py new file mode 100755 index 0000000000..de335ae204 --- /dev/null +++ b/tools/utils/contrib/elftools/construct/__init__.py @@ -0,0 +1,110 @@ +""" + #### #### + ## #### ## ## #### ###### ##### ## ## #### ###### ## ## + ## ## ## ### ## ## ## ## ## ## ## ## ## #### ## + ## ## ## ###### ### ## ##### ## ## ## ## ## + ## ## ## ## ### ## ## ## ## ## ## ## ## ## + #### #### ## ## #### ## ## ## ##### #### ## ###### + + Parsing made even more fun (and faster too) + +Homepage: + http://construct.wikispaces.com (including online tutorial) + +Typical usage: + >>> from construct import * + +Hands-on example: + >>> from construct import * + >>> s = Struct("foo", + ... UBInt8("a"), + ... UBInt16("b"), + ... ) + >>> s.parse("\\x01\\x02\\x03") + Container(a = 1, b = 515) + >>> print s.parse("\\x01\\x02\\x03") + Container: + a = 1 + b = 515 + >>> s.build(Container(a = 1, b = 0x0203)) + "\\x01\\x02\\x03" +""" + +from .core import * +from .adapters import * +from .macros import * +from .debug import Probe, Debugger + + +#=============================================================================== +# Metadata +#=============================================================================== +__author__ = "tomer filiba (tomerfiliba [at] gmail.com)" +__maintainer__ = "Corbin Simpson " +__version__ = "2.06" + +#=============================================================================== +# Shorthand expressions +#=============================================================================== +Bits = BitField +Byte = UBInt8 +Bytes = Field +Const = ConstAdapter +Tunnel = TunnelAdapter +Embed = Embedded + +#=============================================================================== +# Deprecated names +# Next scheduled name cleanout: 2.1 +#=============================================================================== +import functools, warnings + +def deprecated(f): + @functools.wraps(f) + def wrapper(*args, **kwargs): + warnings.warn( + "This name is deprecated, use %s instead" % f.__name__, + DeprecationWarning, stacklevel=2) + return f(*args, **kwargs) + return wrapper + +MetaBytes = deprecated(MetaField) +GreedyRepeater = deprecated(GreedyRange) +OptionalGreedyRepeater = deprecated(OptionalGreedyRange) +Repeater = deprecated(Range) +StrictRepeater = deprecated(Array) +MetaRepeater = deprecated(Array) +OneOfValidator = deprecated(OneOf) +NoneOfValidator = deprecated(NoneOf) + +#=============================================================================== +# exposed names +#=============================================================================== +__all__ = [ + 'AdaptationError', 'Adapter', 'Alias', 'Aligned', 'AlignedStruct', + 'Anchor', 'Array', 'ArrayError', 'BFloat32', 'BFloat64', 'Bit', 'BitField', + 'BitIntegerAdapter', 'BitIntegerError', 'BitStruct', 'Bits', 'Bitwise', + 'Buffered', 'Byte', 'Bytes', 'CString', 'CStringAdapter', 'Const', + 'ConstAdapter', 'ConstError', 'Construct', 'ConstructError', 'Container', + 'Debugger', 'Embed', 'Embedded', 'EmbeddedBitStruct', 'Enum', 'ExprAdapter', + 'Field', 'FieldError', 'Flag', 'FlagsAdapter', 'FlagsContainer', + 'FlagsEnum', 'FormatField', 'GreedyRange', 'GreedyRepeater', + 'HexDumpAdapter', 'If', 'IfThenElse', 'IndexingAdapter', 'LFloat32', + 'LFloat64', 'LazyBound', 'LengthValueAdapter', 'ListContainer', + 'MappingAdapter', 'MappingError', 'MetaArray', 'MetaBytes', 'MetaField', + 'MetaRepeater', 'NFloat32', 'NFloat64', 'Nibble', 'NoneOf', + 'NoneOfValidator', 'Octet', 'OnDemand', 'OnDemandPointer', 'OneOf', + 'OneOfValidator', 'OpenRange', 'Optional', 'OptionalGreedyRange', + 'OptionalGreedyRepeater', 'PaddedStringAdapter', 'Padding', + 'PaddingAdapter', 'PaddingError', 'PascalString', 'Pass', 'Peek', + 'Pointer', 'PrefixedArray', 'Probe', 'Range', 'RangeError', 'Reconfig', + 'Rename', 'RepeatUntil', 'Repeater', 'Restream', 'SBInt16', 'SBInt32', + 'SBInt64', 'SBInt8', 'SLInt16', 'SLInt32', 'SLInt64', 'SLInt8', 'SNInt16', + 'SNInt32', 'SNInt64', 'SNInt8', 'Select', 'SelectError', 'Sequence', + 'SizeofError', 'SlicingAdapter', 'StaticField', 'StrictRepeater', 'String', + 'StringAdapter', 'Struct', 'Subconstruct', 'Switch', 'SwitchError', + 'SymmetricMapping', 'Terminator', 'TerminatorError', 'Tunnel', + 'TunnelAdapter', 'UBInt16', 'UBInt32', 'UBInt64', 'UBInt8', 'ULInt16', + 'ULInt32', 'ULInt64', 'ULInt8', 'UNInt16', 'UNInt32', 'UNInt64', 'UNInt8', + 'Union', 'ValidationError', 'Validator', 'Value', "Magic", +] diff --git a/tools/utils/contrib/elftools/construct/adapters.py b/tools/utils/contrib/elftools/construct/adapters.py new file mode 100755 index 0000000000..26e5c67bf4 --- /dev/null +++ b/tools/utils/contrib/elftools/construct/adapters.py @@ -0,0 +1,470 @@ +from .core import Adapter, AdaptationError, Pass +from .lib import int_to_bin, bin_to_int, swap_bytes +from .lib import FlagsContainer, HexString +from .lib.py3compat import BytesIO, decodebytes + + +#=============================================================================== +# exceptions +#=============================================================================== +class BitIntegerError(AdaptationError): + __slots__ = [] +class MappingError(AdaptationError): + __slots__ = [] +class ConstError(AdaptationError): + __slots__ = [] +class ValidationError(AdaptationError): + __slots__ = [] +class PaddingError(AdaptationError): + __slots__ = [] + +#=============================================================================== +# adapters +#=============================================================================== +class BitIntegerAdapter(Adapter): + """ + Adapter for bit-integers (converts bitstrings to integers, and vice versa). + See BitField. + + Parameters: + * subcon - the subcon to adapt + * width - the size of the subcon, in bits + * swapped - whether to swap byte order (little endian/big endian). + default is False (big endian) + * signed - whether the value is signed (two's complement). the default + is False (unsigned) + * bytesize - number of bits per byte, used for byte-swapping (if swapped). + default is 8. + """ + __slots__ = ["width", "swapped", "signed", "bytesize"] + def __init__(self, subcon, width, swapped = False, signed = False, + bytesize = 8): + Adapter.__init__(self, subcon) + self.width = width + self.swapped = swapped + self.signed = signed + self.bytesize = bytesize + def _encode(self, obj, context): + if obj < 0 and not self.signed: + raise BitIntegerError("object is negative, but field is not signed", + obj) + obj2 = int_to_bin(obj, width = self.width) + if self.swapped: + obj2 = swap_bytes(obj2, bytesize = self.bytesize) + return obj2 + def _decode(self, obj, context): + if self.swapped: + obj = swap_bytes(obj, bytesize = self.bytesize) + return bin_to_int(obj, signed = self.signed) + +class MappingAdapter(Adapter): + """ + Adapter that maps objects to other objects. + See SymmetricMapping and Enum. + + Parameters: + * subcon - the subcon to map + * decoding - the decoding (parsing) mapping (a dict) + * encoding - the encoding (building) mapping (a dict) + * decdefault - the default return value when the object is not found + in the decoding mapping. if no object is given, an exception is raised. + if `Pass` is used, the unmapped object will be passed as-is + * encdefault - the default return value when the object is not found + in the encoding mapping. if no object is given, an exception is raised. + if `Pass` is used, the unmapped object will be passed as-is + """ + __slots__ = ["encoding", "decoding", "encdefault", "decdefault"] + def __init__(self, subcon, decoding, encoding, + decdefault = NotImplemented, encdefault = NotImplemented): + Adapter.__init__(self, subcon) + self.decoding = decoding + self.encoding = encoding + self.decdefault = decdefault + self.encdefault = encdefault + def _encode(self, obj, context): + try: + return self.encoding[obj] + except (KeyError, TypeError): + if self.encdefault is NotImplemented: + raise MappingError("no encoding mapping for %r [%s]" % ( + obj, self.subcon.name)) + if self.encdefault is Pass: + return obj + return self.encdefault + def _decode(self, obj, context): + try: + return self.decoding[obj] + except (KeyError, TypeError): + if self.decdefault is NotImplemented: + raise MappingError("no decoding mapping for %r [%s]" % ( + obj, self.subcon.name)) + if self.decdefault is Pass: + return obj + return self.decdefault + +class FlagsAdapter(Adapter): + """ + Adapter for flag fields. Each flag is extracted from the number, resulting + in a FlagsContainer object. Not intended for direct usage. + See FlagsEnum. + + Parameters + * subcon - the subcon to extract + * flags - a dictionary mapping flag-names to their value + """ + __slots__ = ["flags"] + def __init__(self, subcon, flags): + Adapter.__init__(self, subcon) + self.flags = flags + def _encode(self, obj, context): + flags = 0 + for name, value in self.flags.items(): + if getattr(obj, name, False): + flags |= value + return flags + def _decode(self, obj, context): + obj2 = FlagsContainer() + for name, value in self.flags.items(): + setattr(obj2, name, bool(obj & value)) + return obj2 + +class StringAdapter(Adapter): + """ + Adapter for strings. Converts a sequence of characters into a python + string, and optionally handles character encoding. + See String. + + Parameters: + * subcon - the subcon to convert + * encoding - the character encoding name (e.g., "utf8"), or None to + return raw bytes (usually 8-bit ASCII). + """ + __slots__ = ["encoding"] + def __init__(self, subcon, encoding = None): + Adapter.__init__(self, subcon) + self.encoding = encoding + def _encode(self, obj, context): + if self.encoding: + obj = obj.encode(self.encoding) + return obj + def _decode(self, obj, context): + if self.encoding: + obj = obj.decode(self.encoding) + return obj + +class PaddedStringAdapter(Adapter): + r""" + Adapter for padded strings. + See String. + + Parameters: + * subcon - the subcon to adapt + * padchar - the padding character. default is "\x00". + * paddir - the direction where padding is placed ("right", "left", or + "center"). the default is "right". + * trimdir - the direction where trimming will take place ("right" or + "left"). the default is "right". trimming is only meaningful for + building, when the given string is too long. + """ + __slots__ = ["padchar", "paddir", "trimdir"] + def __init__(self, subcon, padchar = "\x00", paddir = "right", + trimdir = "right"): + if paddir not in ("right", "left", "center"): + raise ValueError("paddir must be 'right', 'left' or 'center'", + paddir) + if trimdir not in ("right", "left"): + raise ValueError("trimdir must be 'right' or 'left'", trimdir) + Adapter.__init__(self, subcon) + self.padchar = padchar + self.paddir = paddir + self.trimdir = trimdir + def _decode(self, obj, context): + if self.paddir == "right": + obj = obj.rstrip(self.padchar) + elif self.paddir == "left": + obj = obj.lstrip(self.padchar) + else: + obj = obj.strip(self.padchar) + return obj + def _encode(self, obj, context): + size = self._sizeof(context) + if self.paddir == "right": + obj = obj.ljust(size, self.padchar) + elif self.paddir == "left": + obj = obj.rjust(size, self.padchar) + else: + obj = obj.center(size, self.padchar) + if len(obj) > size: + if self.trimdir == "right": + obj = obj[:size] + else: + obj = obj[-size:] + return obj + +class LengthValueAdapter(Adapter): + """ + Adapter for length-value pairs. It extracts only the value from the + pair, and calculates the length based on the value. + See PrefixedArray and PascalString. + + Parameters: + * subcon - the subcon returning a length-value pair + """ + __slots__ = [] + def _encode(self, obj, context): + return (len(obj), obj) + def _decode(self, obj, context): + return obj[1] + +class CStringAdapter(StringAdapter): + r""" + Adapter for C-style strings (strings terminated by a terminator char). + + Parameters: + * subcon - the subcon to convert + * terminators - a sequence of terminator chars. default is "\x00". + * encoding - the character encoding to use (e.g., "utf8"), or None to + return raw-bytes. the terminator characters are not affected by the + encoding. + """ + __slots__ = ["terminators"] + def __init__(self, subcon, terminators = b"\x00", encoding = None): + StringAdapter.__init__(self, subcon, encoding = encoding) + self.terminators = terminators + def _encode(self, obj, context): + return StringAdapter._encode(self, obj, context) + self.terminators[0:1] + def _decode(self, obj, context): + return StringAdapter._decode(self, b''.join(obj[:-1]), context) + +class TunnelAdapter(Adapter): + """ + Adapter for tunneling (as in protocol tunneling). A tunnel is construct + nested upon another (layering). For parsing, the lower layer first parses + the data (note: it must return a string!), then the upper layer is called + to parse that data (bottom-up). For building it works in a top-down manner; + first the upper layer builds the data, then the lower layer takes it and + writes it to the stream. + + Parameters: + * subcon - the lower layer subcon + * inner_subcon - the upper layer (tunneled/nested) subcon + + Example: + # a pascal string containing compressed data (zlib encoding), so first + # the string is read, decompressed, and finally re-parsed as an array + # of UBInt16 + TunnelAdapter( + PascalString("data", encoding = "zlib"), + GreedyRange(UBInt16("elements")) + ) + """ + __slots__ = ["inner_subcon"] + def __init__(self, subcon, inner_subcon): + Adapter.__init__(self, subcon) + self.inner_subcon = inner_subcon + def _decode(self, obj, context): + return self.inner_subcon._parse(BytesIO(obj), context) + def _encode(self, obj, context): + stream = BytesIO() + self.inner_subcon._build(obj, stream, context) + return stream.getvalue() + +class ExprAdapter(Adapter): + """ + A generic adapter that accepts 'encoder' and 'decoder' as parameters. You + can use ExprAdapter instead of writing a full-blown class when only a + simple expression is needed. + + Parameters: + * subcon - the subcon to adapt + * encoder - a function that takes (obj, context) and returns an encoded + version of obj + * decoder - a function that takes (obj, context) and returns an decoded + version of obj + + Example: + ExprAdapter(UBInt8("foo"), + encoder = lambda obj, ctx: obj / 4, + decoder = lambda obj, ctx: obj * 4, + ) + """ + __slots__ = ["_encode", "_decode"] + def __init__(self, subcon, encoder, decoder): + Adapter.__init__(self, subcon) + self._encode = encoder + self._decode = decoder + +class HexDumpAdapter(Adapter): + """ + Adapter for hex-dumping strings. It returns a HexString, which is a string + """ + __slots__ = ["linesize"] + def __init__(self, subcon, linesize = 16): + Adapter.__init__(self, subcon) + self.linesize = linesize + def _encode(self, obj, context): + return obj + def _decode(self, obj, context): + return HexString(obj, linesize = self.linesize) + +class ConstAdapter(Adapter): + """ + Adapter for enforcing a constant value ("magic numbers"). When decoding, + the return value is checked; when building, the value is substituted in. + + Parameters: + * subcon - the subcon to validate + * value - the expected value + + Example: + Const(Field("signature", 2), "MZ") + """ + __slots__ = ["value"] + def __init__(self, subcon, value): + Adapter.__init__(self, subcon) + self.value = value + def _encode(self, obj, context): + if obj is None or obj == self.value: + return self.value + else: + raise ConstError("expected %r, found %r" % (self.value, obj)) + def _decode(self, obj, context): + if obj != self.value: + raise ConstError("expected %r, found %r" % (self.value, obj)) + return obj + +class SlicingAdapter(Adapter): + """ + Adapter for slicing a list (getting a slice from that list) + + Parameters: + * subcon - the subcon to slice + * start - start index + * stop - stop index (or None for up-to-end) + * step - step (or None for every element) + """ + __slots__ = ["start", "stop", "step"] + def __init__(self, subcon, start, stop = None): + Adapter.__init__(self, subcon) + self.start = start + self.stop = stop + def _encode(self, obj, context): + if self.start is None: + return obj + return [None] * self.start + obj + def _decode(self, obj, context): + return obj[self.start:self.stop] + +class IndexingAdapter(Adapter): + """ + Adapter for indexing a list (getting a single item from that list) + + Parameters: + * subcon - the subcon to index + * index - the index of the list to get + """ + __slots__ = ["index"] + def __init__(self, subcon, index): + Adapter.__init__(self, subcon) + if type(index) is not int: + raise TypeError("index must be an integer", type(index)) + self.index = index + def _encode(self, obj, context): + return [None] * self.index + [obj] + def _decode(self, obj, context): + return obj[self.index] + +class PaddingAdapter(Adapter): + r""" + Adapter for padding. + + Parameters: + * subcon - the subcon to pad + * pattern - the padding pattern (character). default is "\x00" + * strict - whether or not to verify, during parsing, that the given + padding matches the padding pattern. default is False (unstrict) + """ + __slots__ = ["pattern", "strict"] + def __init__(self, subcon, pattern = "\x00", strict = False): + Adapter.__init__(self, subcon) + self.pattern = pattern + self.strict = strict + def _encode(self, obj, context): + return self._sizeof(context) * self.pattern + def _decode(self, obj, context): + if self.strict: + expected = self._sizeof(context) * self.pattern + if obj != expected: + raise PaddingError("expected %r, found %r" % (expected, obj)) + return obj + + +#=============================================================================== +# validators +#=============================================================================== +class Validator(Adapter): + """ + Abstract class: validates a condition on the encoded/decoded object. + Override _validate(obj, context) in deriving classes. + + Parameters: + * subcon - the subcon to validate + """ + __slots__ = [] + def _decode(self, obj, context): + if not self._validate(obj, context): + raise ValidationError("invalid object", obj) + return obj + def _encode(self, obj, context): + return self._decode(obj, context) + def _validate(self, obj, context): + raise NotImplementedError() + +class OneOf(Validator): + """ + Validates that the object is one of the listed values. + + :param ``Construct`` subcon: object to validate + :param iterable valids: a set of valid values + + >>> OneOf(UBInt8("foo"), [4,5,6,7]).parse("\\x05") + 5 + >>> OneOf(UBInt8("foo"), [4,5,6,7]).parse("\\x08") + Traceback (most recent call last): + ... + construct.core.ValidationError: ('invalid object', 8) + >>> + >>> OneOf(UBInt8("foo"), [4,5,6,7]).build(5) + '\\x05' + >>> OneOf(UBInt8("foo"), [4,5,6,7]).build(9) + Traceback (most recent call last): + ... + construct.core.ValidationError: ('invalid object', 9) + """ + __slots__ = ["valids"] + def __init__(self, subcon, valids): + Validator.__init__(self, subcon) + self.valids = valids + def _validate(self, obj, context): + return obj in self.valids + +class NoneOf(Validator): + """ + Validates that the object is none of the listed values. + + :param ``Construct`` subcon: object to validate + :param iterable invalids: a set of invalid values + + >>> NoneOf(UBInt8("foo"), [4,5,6,7]).parse("\\x08") + 8 + >>> NoneOf(UBInt8("foo"), [4,5,6,7]).parse("\\x06") + Traceback (most recent call last): + ... + construct.core.ValidationError: ('invalid object', 6) + """ + __slots__ = ["invalids"] + def __init__(self, subcon, invalids): + Validator.__init__(self, subcon) + self.invalids = invalids + def _validate(self, obj, context): + return obj not in self.invalids diff --git a/tools/utils/contrib/elftools/construct/core.py b/tools/utils/contrib/elftools/construct/core.py new file mode 100755 index 0000000000..214c58fc08 --- /dev/null +++ b/tools/utils/contrib/elftools/construct/core.py @@ -0,0 +1,1324 @@ +from struct import Struct as Packer + +from .lib.py3compat import BytesIO, advance_iterator, bchr +from .lib import Container, ListContainer, LazyContainer + + +#=============================================================================== +# exceptions +#=============================================================================== +class ConstructError(Exception): + __slots__ = [] +class FieldError(ConstructError): + __slots__ = [] +class SizeofError(ConstructError): + __slots__ = [] +class AdaptationError(ConstructError): + __slots__ = [] +class ArrayError(ConstructError): + __slots__ = [] +class RangeError(ConstructError): + __slots__ = [] +class SwitchError(ConstructError): + __slots__ = [] +class SelectError(ConstructError): + __slots__ = [] +class TerminatorError(ConstructError): + __slots__ = [] + +#=============================================================================== +# abstract constructs +#=============================================================================== +class Construct(object): + """ + The mother of all constructs. + + This object is generally not directly instantiated, and it does not + directly implement parsing and building, so it is largely only of interest + to subclass implementors. + + The external user API: + + * parse() + * parse_stream() + * build() + * build_stream() + * sizeof() + + Subclass authors should not override the external methods. Instead, + another API is available: + + * _parse() + * _build() + * _sizeof() + + There is also a flag API: + + * _set_flag() + * _clear_flag() + * _inherit_flags() + * _is_flag() + + And stateful copying: + + * __getstate__() + * __setstate__() + + Attributes and Inheritance + ========================== + + All constructs have a name and flags. The name is used for naming struct + members and context dictionaries. Note that the name can either be a + string, or None if the name is not needed. A single underscore ("_") is a + reserved name, and so are names starting with a less-than character ("<"). + The name should be descriptive, short, and valid as a Python identifier, + although these rules are not enforced. + + The flags specify additional behavioral information about this construct. + Flags are used by enclosing constructs to determine a proper course of + action. Flags are inherited by default, from inner subconstructs to outer + constructs. The enclosing construct may set new flags or clear existing + ones, as necessary. + + For example, if FLAG_COPY_CONTEXT is set, repeaters will pass a copy of + the context for each iteration, which is necessary for OnDemand parsing. + """ + + FLAG_COPY_CONTEXT = 0x0001 + FLAG_DYNAMIC = 0x0002 + FLAG_EMBED = 0x0004 + FLAG_NESTING = 0x0008 + + __slots__ = ["name", "conflags"] + def __init__(self, name, flags = 0): + if name is not None: + if type(name) is not str: + raise TypeError("name must be a string or None", name) + if name == "_" or name.startswith("<"): + raise ValueError("reserved name", name) + self.name = name + self.conflags = flags + + def __repr__(self): + return "%s(%r)" % (self.__class__.__name__, self.name) + + def _set_flag(self, flag): + """ + Set the given flag or flags. + + :param int flag: flag to set; may be OR'd combination of flags + """ + + self.conflags |= flag + + def _clear_flag(self, flag): + """ + Clear the given flag or flags. + + :param int flag: flag to clear; may be OR'd combination of flags + """ + + self.conflags &= ~flag + + def _inherit_flags(self, *subcons): + """ + Pull flags from subconstructs. + """ + + for sc in subcons: + self._set_flag(sc.conflags) + + def _is_flag(self, flag): + """ + Check whether a given flag is set. + + :param int flag: flag to check + """ + + return bool(self.conflags & flag) + + def __getstate__(self): + """ + Obtain a dictionary representing this construct's state. + """ + + attrs = {} + if hasattr(self, "__dict__"): + attrs.update(self.__dict__) + slots = [] + c = self.__class__ + while c is not None: + if hasattr(c, "__slots__"): + slots.extend(c.__slots__) + c = c.__base__ + for name in slots: + if hasattr(self, name): + attrs[name] = getattr(self, name) + return attrs + + def __setstate__(self, attrs): + """ + Set this construct's state to a given state. + """ + for name, value in attrs.items(): + setattr(self, name, value) + + def __copy__(self): + """returns a copy of this construct""" + self2 = object.__new__(self.__class__) + self2.__setstate__(self.__getstate__()) + return self2 + + def parse(self, data): + """ + Parse an in-memory buffer. + + Strings, buffers, memoryviews, and other complete buffers can be + parsed with this method. + """ + + return self.parse_stream(BytesIO(data)) + + def parse_stream(self, stream): + """ + Parse a stream. + + Files, pipes, sockets, and other streaming sources of data are handled + by this method. + """ + + return self._parse(stream, Container()) + + def _parse(self, stream, context): + """ + Override me in your subclass. + """ + + raise NotImplementedError() + + def build(self, obj): + """ + Build an object in memory. + """ + stream = BytesIO() + self.build_stream(obj, stream) + return stream.getvalue() + + def build_stream(self, obj, stream): + """ + Build an object directly into a stream. + """ + self._build(obj, stream, Container()) + + def _build(self, obj, stream, context): + """ + Override me in your subclass. + """ + + raise NotImplementedError() + + def sizeof(self, context=None): + """ + Calculate the size of this object, optionally using a context. + + Some constructs have no fixed size and can only know their size for a + given hunk of data; these constructs will raise an error if they are + not passed a context. + + :param ``Container`` context: contextual data + + :returns: int of the length of this construct + :raises SizeofError: the size could not be determined + """ + + if context is None: + context = Container() + try: + return self._sizeof(context) + except Exception as e: + raise SizeofError(e) + + def _sizeof(self, context): + """ + Override me in your subclass. + """ + + raise SizeofError("Raw Constructs have no size!") + +class Subconstruct(Construct): + """ + Abstract subconstruct (wraps an inner construct, inheriting its + name and flags). + + Parameters: + * subcon - the construct to wrap + """ + __slots__ = ["subcon"] + def __init__(self, subcon): + Construct.__init__(self, subcon.name, subcon.conflags) + self.subcon = subcon + def _parse(self, stream, context): + return self.subcon._parse(stream, context) + def _build(self, obj, stream, context): + self.subcon._build(obj, stream, context) + def _sizeof(self, context): + return self.subcon._sizeof(context) + +class Adapter(Subconstruct): + """ + Abstract adapter: calls _decode for parsing and _encode for building. + + Parameters: + * subcon - the construct to wrap + """ + __slots__ = [] + def _parse(self, stream, context): + return self._decode(self.subcon._parse(stream, context), context) + def _build(self, obj, stream, context): + self.subcon._build(self._encode(obj, context), stream, context) + def _decode(self, obj, context): + raise NotImplementedError() + def _encode(self, obj, context): + raise NotImplementedError() + + +#=============================================================================== +# Fields +#=============================================================================== +def _read_stream(stream, length): + if length < 0: + raise ValueError("length must be >= 0", length) + data = stream.read(length) + if len(data) != length: + raise FieldError("expected %d, found %d" % (length, len(data))) + return data + +def _write_stream(stream, length, data): + if length < 0: + raise ValueError("length must be >= 0", length) + if len(data) != length: + raise FieldError("expected %d, found %d" % (length, len(data))) + stream.write(data) + +class StaticField(Construct): + """ + A fixed-size byte field. + + :param str name: field name + :param int length: number of bytes in the field + """ + + __slots__ = ["length"] + def __init__(self, name, length): + Construct.__init__(self, name) + self.length = length + def _parse(self, stream, context): + return _read_stream(stream, self.length) + def _build(self, obj, stream, context): + _write_stream(stream, self.length, obj) + def _sizeof(self, context): + return self.length + +class FormatField(StaticField): + """ + A field that uses ``struct`` to pack and unpack data. + + See ``struct`` documentation for instructions on crafting format strings. + + :param str name: name of the field + :param str endianness: format endianness string; one of "<", ">", or "=" + :param str format: a single format character + """ + + __slots__ = ["packer"] + def __init__(self, name, endianity, format): + if endianity not in (">", "<", "="): + raise ValueError("endianity must be be '=', '<', or '>'", + endianity) + if len(format) != 1: + raise ValueError("must specify one and only one format char") + self.packer = Packer(endianity + format) + StaticField.__init__(self, name, self.packer.size) + def __getstate__(self): + attrs = StaticField.__getstate__(self) + attrs["packer"] = attrs["packer"].format + return attrs + def __setstate__(self, attrs): + attrs["packer"] = Packer(attrs["packer"]) + return StaticField.__setstate__(attrs) + def _parse(self, stream, context): + try: + return self.packer.unpack(_read_stream(stream, self.length))[0] + except Exception as ex: + raise FieldError(ex) + def _build(self, obj, stream, context): + try: + _write_stream(stream, self.length, self.packer.pack(obj)) + except Exception as ex: + raise FieldError(ex) + +class MetaField(Construct): + """ + A variable-length field. The length is obtained at runtime from a + function. + + :param str name: name of the field + :param callable lengthfunc: callable that takes a context and returns + length as an int + + >>> foo = Struct("foo", + ... Byte("length"), + ... MetaField("data", lambda ctx: ctx["length"]) + ... ) + >>> foo.parse("\\x03ABC") + Container(data = 'ABC', length = 3) + >>> foo.parse("\\x04ABCD") + Container(data = 'ABCD', length = 4) + """ + + __slots__ = ["lengthfunc"] + def __init__(self, name, lengthfunc): + Construct.__init__(self, name) + self.lengthfunc = lengthfunc + self._set_flag(self.FLAG_DYNAMIC) + def _parse(self, stream, context): + return _read_stream(stream, self.lengthfunc(context)) + def _build(self, obj, stream, context): + _write_stream(stream, self.lengthfunc(context), obj) + def _sizeof(self, context): + return self.lengthfunc(context) + + +#=============================================================================== +# arrays and repeaters +#=============================================================================== +class MetaArray(Subconstruct): + """ + An array (repeater) of a meta-count. The array will iterate exactly + `countfunc()` times. Will raise ArrayError if less elements are found. + See also Array, Range and RepeatUntil. + + Parameters: + * countfunc - a function that takes the context as a parameter and returns + the number of elements of the array (count) + * subcon - the subcon to repeat `countfunc()` times + + Example: + MetaArray(lambda ctx: 5, UBInt8("foo")) + """ + __slots__ = ["countfunc"] + def __init__(self, countfunc, subcon): + Subconstruct.__init__(self, subcon) + self.countfunc = countfunc + self._clear_flag(self.FLAG_COPY_CONTEXT) + self._set_flag(self.FLAG_DYNAMIC) + def _parse(self, stream, context): + obj = ListContainer() + c = 0 + count = self.countfunc(context) + try: + if self.subcon.conflags & self.FLAG_COPY_CONTEXT: + while c < count: + obj.append(self.subcon._parse(stream, context.__copy__())) + c += 1 + else: + while c < count: + obj.append(self.subcon._parse(stream, context)) + c += 1 + except ConstructError as ex: + raise ArrayError("expected %d, found %d" % (count, c), ex) + return obj + def _build(self, obj, stream, context): + count = self.countfunc(context) + if len(obj) != count: + raise ArrayError("expected %d, found %d" % (count, len(obj))) + if self.subcon.conflags & self.FLAG_COPY_CONTEXT: + for subobj in obj: + self.subcon._build(subobj, stream, context.__copy__()) + else: + for subobj in obj: + self.subcon._build(subobj, stream, context) + def _sizeof(self, context): + return self.subcon._sizeof(context) * self.countfunc(context) + +class Range(Subconstruct): + """ + A range-array. The subcon will iterate between `mincount` to `maxcount` + times. If less than `mincount` elements are found, raises RangeError. + See also GreedyRange and OptionalGreedyRange. + + The general-case repeater. Repeats the given unit for at least mincount + times, and up to maxcount times. If an exception occurs (EOF, validation + error), the repeater exits. If less than mincount units have been + successfully parsed, a RangeError is raised. + + .. note:: + This object requires a seekable stream for parsing. + + :param int mincount: the minimal count + :param int maxcount: the maximal count + :param Construct subcon: the subcon to repeat + + >>> c = Range(3, 7, UBInt8("foo")) + >>> c.parse("\\x01\\x02") + Traceback (most recent call last): + ... + construct.core.RangeError: expected 3..7, found 2 + >>> c.parse("\\x01\\x02\\x03") + [1, 2, 3] + >>> c.parse("\\x01\\x02\\x03\\x04\\x05\\x06") + [1, 2, 3, 4, 5, 6] + >>> c.parse("\\x01\\x02\\x03\\x04\\x05\\x06\\x07") + [1, 2, 3, 4, 5, 6, 7] + >>> c.parse("\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09") + [1, 2, 3, 4, 5, 6, 7] + >>> c.build([1,2]) + Traceback (most recent call last): + ... + construct.core.RangeError: expected 3..7, found 2 + >>> c.build([1,2,3,4]) + '\\x01\\x02\\x03\\x04' + >>> c.build([1,2,3,4,5,6,7,8]) + Traceback (most recent call last): + ... + construct.core.RangeError: expected 3..7, found 8 + """ + + __slots__ = ["mincount", "maxcout"] + def __init__(self, mincount, maxcout, subcon): + Subconstruct.__init__(self, subcon) + self.mincount = mincount + self.maxcout = maxcout + self._clear_flag(self.FLAG_COPY_CONTEXT) + self._set_flag(self.FLAG_DYNAMIC) + def _parse(self, stream, context): + obj = ListContainer() + c = 0 + try: + if self.subcon.conflags & self.FLAG_COPY_CONTEXT: + while c < self.maxcout: + pos = stream.tell() + obj.append(self.subcon._parse(stream, context.__copy__())) + c += 1 + else: + while c < self.maxcout: + pos = stream.tell() + obj.append(self.subcon._parse(stream, context)) + c += 1 + except ConstructError as ex: + if c < self.mincount: + raise RangeError("expected %d to %d, found %d" % + (self.mincount, self.maxcout, c), ex) + stream.seek(pos) + return obj + def _build(self, obj, stream, context): + if len(obj) < self.mincount or len(obj) > self.maxcout: + raise RangeError("expected %d to %d, found %d" % + (self.mincount, self.maxcout, len(obj))) + cnt = 0 + try: + if self.subcon.conflags & self.FLAG_COPY_CONTEXT: + for subobj in obj: + if isinstance(obj, bytes): + subobj = bchr(subobj) + self.subcon._build(subobj, stream, context.__copy__()) + cnt += 1 + else: + for subobj in obj: + if isinstance(obj, bytes): + subobj = bchr(subobj) + self.subcon._build(subobj, stream, context) + cnt += 1 + except ConstructError as ex: + if cnt < self.mincount: + raise RangeError("expected %d to %d, found %d" % + (self.mincount, self.maxcout, len(obj)), ex) + def _sizeof(self, context): + raise SizeofError("can't calculate size") + +class RepeatUntil(Subconstruct): + """ + An array that repeats until the predicate indicates it to stop. Note that + the last element (which caused the repeat to exit) is included in the + return value. + + Parameters: + * predicate - a predicate function that takes (obj, context) and returns + True if the stop-condition is met, or False to continue. + * subcon - the subcon to repeat. + + Example: + # will read chars until b\x00 (inclusive) + RepeatUntil(lambda obj, ctx: obj == b"\x00", + Field("chars", 1) + ) + """ + __slots__ = ["predicate"] + def __init__(self, predicate, subcon): + Subconstruct.__init__(self, subcon) + self.predicate = predicate + self._clear_flag(self.FLAG_COPY_CONTEXT) + self._set_flag(self.FLAG_DYNAMIC) + def _parse(self, stream, context): + obj = [] + try: + if self.subcon.conflags & self.FLAG_COPY_CONTEXT: + while True: + subobj = self.subcon._parse(stream, context.__copy__()) + obj.append(subobj) + if self.predicate(subobj, context): + break + else: + while True: + subobj = self.subcon._parse(stream, context) + obj.append(subobj) + if self.predicate(subobj, context): + break + except ConstructError as ex: + raise ArrayError("missing terminator", ex) + return obj + def _build(self, obj, stream, context): + terminated = False + if self.subcon.conflags & self.FLAG_COPY_CONTEXT: + for subobj in obj: + self.subcon._build(subobj, stream, context.__copy__()) + if self.predicate(subobj, context): + terminated = True + break + else: + for subobj in obj: + subobj = bchr(subobj) + self.subcon._build(subobj, stream, context.__copy__()) + if self.predicate(subobj, context): + terminated = True + break + if not terminated: + raise ArrayError("missing terminator") + def _sizeof(self, context): + raise SizeofError("can't calculate size") + + +#=============================================================================== +# structures and sequences +#=============================================================================== +class Struct(Construct): + """ + A sequence of named constructs, similar to structs in C. The elements are + parsed and built in the order they are defined. + See also Embedded. + + Parameters: + * name - the name of the structure + * subcons - a sequence of subconstructs that make up this structure. + * nested - a keyword-only argument that indicates whether this struct + creates a nested context. The default is True. This parameter is + considered "advanced usage", and may be removed in the future. + + Example: + Struct("foo", + UBInt8("first_element"), + UBInt16("second_element"), + Padding(2), + UBInt8("third_element"), + ) + """ + __slots__ = ["subcons", "nested"] + def __init__(self, name, *subcons, **kw): + self.nested = kw.pop("nested", True) + if kw: + raise TypeError("the only keyword argument accepted is 'nested'", kw) + Construct.__init__(self, name) + self.subcons = subcons + self._inherit_flags(*subcons) + self._clear_flag(self.FLAG_EMBED) + def _parse(self, stream, context): + if "" in context: + obj = context[""] + del context[""] + else: + obj = Container() + if self.nested: + context = Container(_ = context) + for sc in self.subcons: + if sc.conflags & self.FLAG_EMBED: + context[""] = obj + sc._parse(stream, context) + else: + subobj = sc._parse(stream, context) + if sc.name is not None: + obj[sc.name] = subobj + context[sc.name] = subobj + return obj + def _build(self, obj, stream, context): + if "" in context: + del context[""] + elif self.nested: + context = Container(_ = context) + for sc in self.subcons: + if sc.conflags & self.FLAG_EMBED: + context[""] = True + subobj = obj + elif sc.name is None: + subobj = None + else: + subobj = getattr(obj, sc.name) + context[sc.name] = subobj + sc._build(subobj, stream, context) + def _sizeof(self, context): + if self.nested: + context = Container(_ = context) + return sum(sc._sizeof(context) for sc in self.subcons) + +class Sequence(Struct): + """ + A sequence of unnamed constructs. The elements are parsed and built in the + order they are defined. + See also Embedded. + + Parameters: + * name - the name of the structure + * subcons - a sequence of subconstructs that make up this structure. + * nested - a keyword-only argument that indicates whether this struct + creates a nested context. The default is True. This parameter is + considered "advanced usage", and may be removed in the future. + + Example: + Sequence("foo", + UBInt8("first_element"), + UBInt16("second_element"), + Padding(2), + UBInt8("third_element"), + ) + """ + __slots__ = [] + def _parse(self, stream, context): + if "" in context: + obj = context[""] + del context[""] + else: + obj = ListContainer() + if self.nested: + context = Container(_ = context) + for sc in self.subcons: + if sc.conflags & self.FLAG_EMBED: + context[""] = obj + sc._parse(stream, context) + else: + subobj = sc._parse(stream, context) + if sc.name is not None: + obj.append(subobj) + context[sc.name] = subobj + return obj + def _build(self, obj, stream, context): + if "" in context: + del context[""] + elif self.nested: + context = Container(_ = context) + objiter = iter(obj) + for sc in self.subcons: + if sc.conflags & self.FLAG_EMBED: + context[""] = True + subobj = objiter + elif sc.name is None: + subobj = None + else: + subobj = advance_iterator(objiter) + context[sc.name] = subobj + sc._build(subobj, stream, context) + +class Union(Construct): + """ + a set of overlapping fields (like unions in C). when parsing, + all fields read the same data; when building, only the first subcon + (called "master") is used. + + Parameters: + * name - the name of the union + * master - the master subcon, i.e., the subcon used for building and + calculating the total size + * subcons - additional subcons + + Example: + Union("what_are_four_bytes", + UBInt32("one_dword"), + Struct("two_words", UBInt16("first"), UBInt16("second")), + Struct("four_bytes", + UBInt8("a"), + UBInt8("b"), + UBInt8("c"), + UBInt8("d") + ), + ) + """ + __slots__ = ["parser", "builder"] + def __init__(self, name, master, *subcons, **kw): + Construct.__init__(self, name) + args = [Peek(sc) for sc in subcons] + args.append(MetaField(None, lambda ctx: master._sizeof(ctx))) + self.parser = Struct(name, Peek(master, perform_build = True), *args) + self.builder = Struct(name, master) + def _parse(self, stream, context): + return self.parser._parse(stream, context) + def _build(self, obj, stream, context): + return self.builder._build(obj, stream, context) + def _sizeof(self, context): + return self.builder._sizeof(context) + +#=============================================================================== +# conditional +#=============================================================================== +class Switch(Construct): + """ + A conditional branch. Switch will choose the case to follow based on + the return value of keyfunc. If no case is matched, and no default value + is given, SwitchError will be raised. + See also Pass. + + Parameters: + * name - the name of the construct + * keyfunc - a function that takes the context and returns a key, which + will ne used to choose the relevant case. + * cases - a dictionary mapping keys to constructs. the keys can be any + values that may be returned by keyfunc. + * default - a default value to use when the key is not found in the cases. + if not supplied, an exception will be raised when the key is not found. + You can use the builtin construct Pass for 'do-nothing'. + * include_key - whether or not to include the key in the return value + of parsing. defualt is False. + + Example: + Struct("foo", + UBInt8("type"), + Switch("value", lambda ctx: ctx.type, { + 1 : UBInt8("spam"), + 2 : UBInt16("spam"), + 3 : UBInt32("spam"), + 4 : UBInt64("spam"), + } + ), + ) + """ + + class NoDefault(Construct): + def _parse(self, stream, context): + raise SwitchError("no default case defined") + def _build(self, obj, stream, context): + raise SwitchError("no default case defined") + def _sizeof(self, context): + raise SwitchError("no default case defined") + NoDefault = NoDefault("No default value specified") + + __slots__ = ["subcons", "keyfunc", "cases", "default", "include_key"] + + def __init__(self, name, keyfunc, cases, default = NoDefault, + include_key = False): + Construct.__init__(self, name) + self._inherit_flags(*cases.values()) + self.keyfunc = keyfunc + self.cases = cases + self.default = default + self.include_key = include_key + self._inherit_flags(*cases.values()) + self._set_flag(self.FLAG_DYNAMIC) + def _parse(self, stream, context): + key = self.keyfunc(context) + obj = self.cases.get(key, self.default)._parse(stream, context) + if self.include_key: + return key, obj + else: + return obj + def _build(self, obj, stream, context): + if self.include_key: + key, obj = obj + else: + key = self.keyfunc(context) + case = self.cases.get(key, self.default) + case._build(obj, stream, context) + def _sizeof(self, context): + case = self.cases.get(self.keyfunc(context), self.default) + return case._sizeof(context) + +class Select(Construct): + """ + Selects the first matching subconstruct. It will literally try each of + the subconstructs, until one matches. + + Notes: + * requires a seekable stream. + + Parameters: + * name - the name of the construct + * subcons - the subcons to try (order-sensitive) + * include_name - a keyword only argument, indicating whether to include + the name of the selected subcon in the return value of parsing. default + is false. + + Example: + Select("foo", + UBInt64("large"), + UBInt32("medium"), + UBInt16("small"), + UBInt8("tiny"), + ) + """ + __slots__ = ["subcons", "include_name"] + def __init__(self, name, *subcons, **kw): + include_name = kw.pop("include_name", False) + if kw: + raise TypeError("the only keyword argument accepted " + "is 'include_name'", kw) + Construct.__init__(self, name) + self.subcons = subcons + self.include_name = include_name + self._inherit_flags(*subcons) + self._set_flag(self.FLAG_DYNAMIC) + def _parse(self, stream, context): + for sc in self.subcons: + pos = stream.tell() + context2 = context.__copy__() + try: + obj = sc._parse(stream, context2) + except ConstructError: + stream.seek(pos) + else: + context.__update__(context2) + if self.include_name: + return sc.name, obj + else: + return obj + raise SelectError("no subconstruct matched") + def _build(self, obj, stream, context): + if self.include_name: + name, obj = obj + for sc in self.subcons: + if sc.name == name: + sc._build(obj, stream, context) + return + else: + for sc in self.subcons: + stream2 = BytesIO() + context2 = context.__copy__() + try: + sc._build(obj, stream2, context2) + except Exception: + pass + else: + context.__update__(context2) + stream.write(stream2.getvalue()) + return + raise SelectError("no subconstruct matched", obj) + def _sizeof(self, context): + raise SizeofError("can't calculate size") + + +#=============================================================================== +# stream manipulation +#=============================================================================== +class Pointer(Subconstruct): + """ + Changes the stream position to a given offset, where the construction + should take place, and restores the stream position when finished. + See also Anchor, OnDemand and OnDemandPointer. + + Notes: + * requires a seekable stream. + + Parameters: + * offsetfunc: a function that takes the context and returns an absolute + stream position, where the construction would take place + * subcon - the subcon to use at `offsetfunc()` + + Example: + Struct("foo", + UBInt32("spam_pointer"), + Pointer(lambda ctx: ctx.spam_pointer, + Array(5, UBInt8("spam")) + ) + ) + """ + __slots__ = ["offsetfunc"] + def __init__(self, offsetfunc, subcon): + Subconstruct.__init__(self, subcon) + self.offsetfunc = offsetfunc + def _parse(self, stream, context): + newpos = self.offsetfunc(context) + origpos = stream.tell() + stream.seek(newpos) + obj = self.subcon._parse(stream, context) + stream.seek(origpos) + return obj + def _build(self, obj, stream, context): + newpos = self.offsetfunc(context) + origpos = stream.tell() + stream.seek(newpos) + self.subcon._build(obj, stream, context) + stream.seek(origpos) + def _sizeof(self, context): + return 0 + +class Peek(Subconstruct): + """ + Peeks at the stream: parses without changing the stream position. + See also Union. If the end of the stream is reached when peeking, + returns None. + + Notes: + * requires a seekable stream. + + Parameters: + * subcon - the subcon to peek at + * perform_build - whether or not to perform building. by default this + parameter is set to False, meaning building is a no-op. + + Example: + Peek(UBInt8("foo")) + """ + __slots__ = ["perform_build"] + def __init__(self, subcon, perform_build = False): + Subconstruct.__init__(self, subcon) + self.perform_build = perform_build + def _parse(self, stream, context): + pos = stream.tell() + try: + return self.subcon._parse(stream, context) + except FieldError: + pass + finally: + stream.seek(pos) + def _build(self, obj, stream, context): + if self.perform_build: + self.subcon._build(obj, stream, context) + def _sizeof(self, context): + return 0 + +class OnDemand(Subconstruct): + """ + Allows for on-demand (lazy) parsing. When parsing, it will return a + LazyContainer that represents a pointer to the data, but does not actually + parses it from stream until it's "demanded". + By accessing the 'value' property of LazyContainers, you will demand the + data from the stream. The data will be parsed and cached for later use. + You can use the 'has_value' property to know whether the data has already + been demanded. + See also OnDemandPointer. + + Notes: + * requires a seekable stream. + + Parameters: + * subcon - + * advance_stream - whether or not to advance the stream position. by + default this is True, but if subcon is a pointer, this should be False. + * force_build - whether or not to force build. If set to False, and the + LazyContainer has not been demaned, building is a no-op. + + Example: + OnDemand(Array(10000, UBInt8("foo")) + """ + __slots__ = ["advance_stream", "force_build"] + def __init__(self, subcon, advance_stream = True, force_build = True): + Subconstruct.__init__(self, subcon) + self.advance_stream = advance_stream + self.force_build = force_build + def _parse(self, stream, context): + obj = LazyContainer(self.subcon, stream, stream.tell(), context) + if self.advance_stream: + stream.seek(self.subcon._sizeof(context), 1) + return obj + def _build(self, obj, stream, context): + if not isinstance(obj, LazyContainer): + self.subcon._build(obj, stream, context) + elif self.force_build or obj.has_value: + self.subcon._build(obj.value, stream, context) + elif self.advance_stream: + stream.seek(self.subcon._sizeof(context), 1) + +class Buffered(Subconstruct): + """ + Creates an in-memory buffered stream, which can undergo encoding and + decoding prior to being passed on to the subconstruct. + See also Bitwise. + + Note: + * Do not use pointers inside Buffered + + Parameters: + * subcon - the subcon which will operate on the buffer + * encoder - a function that takes a string and returns an encoded + string (used after building) + * decoder - a function that takes a string and returns a decoded + string (used before parsing) + * resizer - a function that takes the size of the subcon and "adjusts" + or "resizes" it according to the encoding/decoding process. + + Example: + Buffered(BitField("foo", 16), + encoder = decode_bin, + decoder = encode_bin, + resizer = lambda size: size / 8, + ) + """ + __slots__ = ["encoder", "decoder", "resizer"] + def __init__(self, subcon, decoder, encoder, resizer): + Subconstruct.__init__(self, subcon) + self.encoder = encoder + self.decoder = decoder + self.resizer = resizer + def _parse(self, stream, context): + data = _read_stream(stream, self._sizeof(context)) + stream2 = BytesIO(self.decoder(data)) + return self.subcon._parse(stream2, context) + def _build(self, obj, stream, context): + size = self._sizeof(context) + stream2 = BytesIO() + self.subcon._build(obj, stream2, context) + data = self.encoder(stream2.getvalue()) + assert len(data) == size + _write_stream(stream, self._sizeof(context), data) + def _sizeof(self, context): + return self.resizer(self.subcon._sizeof(context)) + +class Restream(Subconstruct): + """ + Wraps the stream with a read-wrapper (for parsing) or a + write-wrapper (for building). The stream wrapper can buffer the data + internally, reading it from- or writing it to the underlying stream + as needed. For example, BitStreamReader reads whole bytes from the + underlying stream, but returns them as individual bits. + See also Bitwise. + + When the parsing or building is done, the stream's close method + will be invoked. It can perform any finalization needed for the stream + wrapper, but it must not close the underlying stream. + + Note: + * Do not use pointers inside Restream + + Parameters: + * subcon - the subcon + * stream_reader - the read-wrapper + * stream_writer - the write wrapper + * resizer - a function that takes the size of the subcon and "adjusts" + or "resizes" it according to the encoding/decoding process. + + Example: + Restream(BitField("foo", 16), + stream_reader = BitStreamReader, + stream_writer = BitStreamWriter, + resizer = lambda size: size / 8, + ) + """ + __slots__ = ["stream_reader", "stream_writer", "resizer"] + def __init__(self, subcon, stream_reader, stream_writer, resizer): + Subconstruct.__init__(self, subcon) + self.stream_reader = stream_reader + self.stream_writer = stream_writer + self.resizer = resizer + def _parse(self, stream, context): + stream2 = self.stream_reader(stream) + obj = self.subcon._parse(stream2, context) + stream2.close() + return obj + def _build(self, obj, stream, context): + stream2 = self.stream_writer(stream) + self.subcon._build(obj, stream2, context) + stream2.close() + def _sizeof(self, context): + return self.resizer(self.subcon._sizeof(context)) + + +#=============================================================================== +# miscellaneous +#=============================================================================== +class Reconfig(Subconstruct): + """ + Reconfigures a subconstruct. Reconfig can be used to change the name and + set and clear flags of the inner subcon. + + Parameters: + * name - the new name + * subcon - the subcon to reconfigure + * setflags - the flags to set (default is 0) + * clearflags - the flags to clear (default is 0) + + Example: + Reconfig("foo", UBInt8("bar")) + """ + __slots__ = [] + def __init__(self, name, subcon, setflags = 0, clearflags = 0): + Construct.__init__(self, name, subcon.conflags) + self.subcon = subcon + self._set_flag(setflags) + self._clear_flag(clearflags) + +class Anchor(Construct): + """ + Returns the "anchor" (stream position) at the point where it's inserted. + Useful for adjusting relative offsets to absolute positions, or to measure + sizes of constructs. + absolute pointer = anchor + relative offset + size = anchor_after - anchor_before + See also Pointer. + + Notes: + * requires a seekable stream. + + Parameters: + * name - the name of the anchor + + Example: + Struct("foo", + Anchor("base"), + UBInt8("relative_offset"), + Pointer(lambda ctx: ctx.relative_offset + ctx.base, + UBInt8("data") + ) + ) + """ + __slots__ = [] + def _parse(self, stream, context): + return stream.tell() + def _build(self, obj, stream, context): + context[self.name] = stream.tell() + def _sizeof(self, context): + return 0 + +class Value(Construct): + """ + A computed value. + + Parameters: + * name - the name of the value + * func - a function that takes the context and return the computed value + + Example: + Struct("foo", + UBInt8("width"), + UBInt8("height"), + Value("total_pixels", lambda ctx: ctx.width * ctx.height), + ) + """ + __slots__ = ["func"] + def __init__(self, name, func): + Construct.__init__(self, name) + self.func = func + self._set_flag(self.FLAG_DYNAMIC) + def _parse(self, stream, context): + return self.func(context) + def _build(self, obj, stream, context): + context[self.name] = self.func(context) + def _sizeof(self, context): + return 0 + +#class Dynamic(Construct): +# """ +# Dynamically creates a construct and uses it for parsing and building. +# This allows you to create change the construction tree on the fly. +# Deprecated. +# +# Parameters: +# * name - the name of the construct +# * factoryfunc - a function that takes the context and returns a new +# construct object which will be used for parsing and building. +# +# Example: +# def factory(ctx): +# if ctx.bar == 8: +# return UBInt8("spam") +# if ctx.bar == 9: +# return String("spam", 9) +# +# Struct("foo", +# UBInt8("bar"), +# Dynamic("spam", factory), +# ) +# """ +# __slots__ = ["factoryfunc"] +# def __init__(self, name, factoryfunc): +# Construct.__init__(self, name, self.FLAG_COPY_CONTEXT) +# self.factoryfunc = factoryfunc +# self._set_flag(self.FLAG_DYNAMIC) +# def _parse(self, stream, context): +# return self.factoryfunc(context)._parse(stream, context) +# def _build(self, obj, stream, context): +# return self.factoryfunc(context)._build(obj, stream, context) +# def _sizeof(self, context): +# return self.factoryfunc(context)._sizeof(context) + +class LazyBound(Construct): + """ + Lazily bound construct, useful for constructs that need to make cyclic + references (linked-lists, expression trees, etc.). + + Parameters: + + + Example: + foo = Struct("foo", + UBInt8("bar"), + LazyBound("next", lambda: foo), + ) + """ + __slots__ = ["bindfunc", "bound"] + def __init__(self, name, bindfunc): + Construct.__init__(self, name) + self.bound = None + self.bindfunc = bindfunc + def _parse(self, stream, context): + if self.bound is None: + self.bound = self.bindfunc() + return self.bound._parse(stream, context) + def _build(self, obj, stream, context): + if self.bound is None: + self.bound = self.bindfunc() + self.bound._build(obj, stream, context) + def _sizeof(self, context): + if self.bound is None: + self.bound = self.bindfunc() + return self.bound._sizeof(context) + +class Pass(Construct): + """ + A do-nothing construct, useful as the default case for Switch, or + to indicate Enums. + See also Switch and Enum. + + Notes: + * this construct is a singleton. do not try to instatiate it, as it + will not work... + + Example: + Pass + """ + __slots__ = [] + def _parse(self, stream, context): + pass + def _build(self, obj, stream, context): + assert obj is None + def _sizeof(self, context): + return 0 +Pass = Pass(None) + +class Terminator(Construct): + """ + Asserts the end of the stream has been reached at the point it's placed. + You can use this to ensure no more unparsed data follows. + + Notes: + * this construct is only meaningful for parsing. for building, it's + a no-op. + * this construct is a singleton. do not try to instatiate it, as it + will not work... + + Example: + Terminator + """ + __slots__ = [] + def _parse(self, stream, context): + if stream.read(1): + raise TerminatorError("expected end of stream") + def _build(self, obj, stream, context): + assert obj is None + def _sizeof(self, context): + return 0 +Terminator = Terminator(None) diff --git a/tools/utils/contrib/elftools/construct/debug.py b/tools/utils/contrib/elftools/construct/debug.py new file mode 100755 index 0000000000..6023df9289 --- /dev/null +++ b/tools/utils/contrib/elftools/construct/debug.py @@ -0,0 +1,134 @@ +""" +Debugging utilities for constructs +""" +from __future__ import print_function +import sys +import traceback +import pdb +import inspect +from .core import Construct, Subconstruct +from .lib import HexString, Container, ListContainer + + +class Probe(Construct): + """ + A probe: dumps the context, stack frames, and stream content to the screen + to aid the debugging process. + See also Debugger. + + Parameters: + * name - the display name + * show_stream - whether or not to show stream contents. default is True. + the stream must be seekable. + * show_context - whether or not to show the context. default is True. + * show_stack - whether or not to show the upper stack frames. default + is True. + * stream_lookahead - the number of bytes to dump when show_stack is set. + default is 100. + + Example: + Struct("foo", + UBInt8("a"), + Probe("between a and b"), + UBInt8("b"), + ) + """ + __slots__ = [ + "printname", "show_stream", "show_context", "show_stack", + "stream_lookahead" + ] + counter = 0 + + def __init__(self, name = None, show_stream = True, + show_context = True, show_stack = True, + stream_lookahead = 100): + Construct.__init__(self, None) + if name is None: + Probe.counter += 1 + name = "" % (Probe.counter,) + self.printname = name + self.show_stream = show_stream + self.show_context = show_context + self.show_stack = show_stack + self.stream_lookahead = stream_lookahead + def __repr__(self): + return "%s(%r)" % (self.__class__.__name__, self.printname) + def _parse(self, stream, context): + self.printout(stream, context) + def _build(self, obj, stream, context): + self.printout(stream, context) + def _sizeof(self, context): + return 0 + + def printout(self, stream, context): + obj = Container() + if self.show_stream: + obj.stream_position = stream.tell() + follows = stream.read(self.stream_lookahead) + if not follows: + obj.following_stream_data = "EOF reached" + else: + stream.seek(-len(follows), 1) + obj.following_stream_data = HexString(follows) + print + + if self.show_context: + obj.context = context + + if self.show_stack: + obj.stack = ListContainer() + frames = [s[0] for s in inspect.stack()][1:-1] + frames.reverse() + for f in frames: + a = Container() + a.__update__(f.f_locals) + obj.stack.append(a) + + print("=" * 80) + print("Probe", self.printname) + print(obj) + print("=" * 80) + +class Debugger(Subconstruct): + """ + A pdb-based debugger. When an exception occurs in the subcon, a debugger + will appear and allow you to debug the error (and even fix on-the-fly). + + Parameters: + * subcon - the subcon to debug + + Example: + Debugger( + Enum(UBInt8("foo"), + a = 1, + b = 2, + c = 3 + ) + ) + """ + __slots__ = ["retval"] + def _parse(self, stream, context): + try: + return self.subcon._parse(stream, context) + except Exception: + self.retval = NotImplemented + self.handle_exc("(you can set the value of 'self.retval', " + "which will be returned)") + if self.retval is NotImplemented: + raise + else: + return self.retval + def _build(self, obj, stream, context): + try: + self.subcon._build(obj, stream, context) + except Exception: + self.handle_exc() + def handle_exc(self, msg = None): + print("=" * 80) + print("Debugging exception of %s:" % (self.subcon,)) + print("".join(traceback.format_exception(*sys.exc_info())[1:])) + if msg: + print(msg) + pdb.post_mortem(sys.exc_info()[2]) + print("=" * 80) + diff --git a/tools/utils/contrib/elftools/construct/lib/__init__.py b/tools/utils/contrib/elftools/construct/lib/__init__.py new file mode 100755 index 0000000000..2e09578752 --- /dev/null +++ b/tools/utils/contrib/elftools/construct/lib/__init__.py @@ -0,0 +1,7 @@ +from .binary import ( + int_to_bin, bin_to_int, swap_bytes, encode_bin, decode_bin) +from .bitstream import BitStreamReader, BitStreamWriter +from .container import (Container, FlagsContainer, ListContainer, + LazyContainer) +from .hex import HexString, hexdump + diff --git a/tools/utils/contrib/elftools/construct/lib/binary.py b/tools/utils/contrib/elftools/construct/lib/binary.py new file mode 100755 index 0000000000..c73b887b47 --- /dev/null +++ b/tools/utils/contrib/elftools/construct/lib/binary.py @@ -0,0 +1,118 @@ +from .py3compat import int2byte + + +def int_to_bin(number, width=32): + r""" + Convert an integer into its binary representation in a bytes object. + Width is the amount of bits to generate. If width is larger than the actual + amount of bits required to represent number in binary, sign-extension is + used. If it's smaller, the representation is trimmed to width bits. + Each "bit" is either '\x00' or '\x01'. The MSBit is first. + + Examples: + + >>> int_to_bin(19, 5) + b'\x01\x00\x00\x01\x01' + >>> int_to_bin(19, 8) + b'\x00\x00\x00\x01\x00\x00\x01\x01' + """ + if number < 0: + number += 1 << width + i = width - 1 + bits = bytearray(width) + while number and i >= 0: + bits[i] = number & 1 + number >>= 1 + i -= 1 + return bytes(bits) + + +_bit_values = { + 0: 0, + 1: 1, + 48: 0, # '0' + 49: 1, # '1' + + # The following are for Python 2, in which iteration over a bytes object + # yields single-character bytes and not integers. + '\x00': 0, + '\x01': 1, + '0': 0, + '1': 1, + } + +def bin_to_int(bits, signed=False): + r""" + Logical opposite of int_to_bin. Both '0' and '\x00' are considered zero, + and both '1' and '\x01' are considered one. Set sign to True to interpret + the number as a 2-s complement signed integer. + """ + number = 0 + bias = 0 + ptr = 0 + if signed and _bit_values[bits[0]] == 1: + bits = bits[1:] + bias = 1 << len(bits) + for b in bits: + number <<= 1 + number |= _bit_values[b] + return number - bias + + +def swap_bytes(bits, bytesize=8): + r""" + Bits is a b'' object containing a binary representation. Assuming each + bytesize bits constitute a bytes, perform a endianness byte swap. Example: + + >>> swap_bytes(b'00011011', 2) + b'11100100' + """ + i = 0 + l = len(bits) + output = [b""] * ((l // bytesize) + 1) + j = len(output) - 1 + while i < l: + output[j] = bits[i : i + bytesize] + i += bytesize + j -= 1 + return b"".join(output) + + +_char_to_bin = {} +_bin_to_char = {} +for i in range(256): + ch = int2byte(i) + bin = int_to_bin(i, 8) + # Populate with for both keys i and ch, to support Python 2 & 3 + _char_to_bin[ch] = bin + _char_to_bin[i] = bin + _bin_to_char[bin] = ch + + +def encode_bin(data): + """ + Create a binary representation of the given b'' object. Assume 8-bit + ASCII. Example: + + >>> encode_bin('ab') + b"\x00\x01\x01\x00\x00\x00\x00\x01\x00\x01\x01\x00\x00\x00\x01\x00" + """ + return b"".join(_char_to_bin[ch] for ch in data) + + +def decode_bin(data): + """ + Locical opposite of decode_bin. + """ + if len(data) & 7: + raise ValueError("Data length must be a multiple of 8") + i = 0 + j = 0 + l = len(data) // 8 + chars = [b""] * l + while j < l: + chars[j] = _bin_to_char[data[i:i+8]] + i += 8 + j += 1 + return b"".join(chars) + diff --git a/tools/utils/contrib/elftools/construct/lib/bitstream.py b/tools/utils/contrib/elftools/construct/lib/bitstream.py new file mode 100755 index 0000000000..0c521a423c --- /dev/null +++ b/tools/utils/contrib/elftools/construct/lib/bitstream.py @@ -0,0 +1,77 @@ +from .binary import encode_bin, decode_bin + +class BitStreamReader(object): + + __slots__ = ["substream", "buffer", "total_size"] + + def __init__(self, substream): + self.substream = substream + self.total_size = 0 + self.buffer = "" + + def close(self): + if self.total_size % 8 != 0: + raise ValueError("total size of read data must be a multiple of 8", + self.total_size) + + def tell(self): + return self.substream.tell() + + def seek(self, pos, whence = 0): + self.buffer = "" + self.total_size = 0 + self.substream.seek(pos, whence) + + def read(self, count): + if count < 0: + raise ValueError("count cannot be negative") + + l = len(self.buffer) + if count == 0: + data = "" + elif count <= l: + data = self.buffer[:count] + self.buffer = self.buffer[count:] + else: + data = self.buffer + count -= l + bytes = count // 8 + if count & 7: + bytes += 1 + buf = encode_bin(self.substream.read(bytes)) + data += buf[:count] + self.buffer = buf[count:] + self.total_size += len(data) + return data + +class BitStreamWriter(object): + + __slots__ = ["substream", "buffer", "pos"] + + def __init__(self, substream): + self.substream = substream + self.buffer = [] + self.pos = 0 + + def close(self): + self.flush() + + def flush(self): + bytes = decode_bin("".join(self.buffer)) + self.substream.write(bytes) + self.buffer = [] + self.pos = 0 + + def tell(self): + return self.substream.tell() + self.pos // 8 + + def seek(self, pos, whence = 0): + self.flush() + self.substream.seek(pos, whence) + + def write(self, data): + if not data: + return + if type(data) is not str: + raise TypeError("data must be a string, not %r" % (type(data),)) + self.buffer.append(data) diff --git a/tools/utils/contrib/elftools/construct/lib/container.py b/tools/utils/contrib/elftools/construct/lib/container.py new file mode 100755 index 0000000000..2f89b2dc40 --- /dev/null +++ b/tools/utils/contrib/elftools/construct/lib/container.py @@ -0,0 +1,161 @@ +""" +Various containers. +""" + +from collections import MutableMapping +from pprint import pformat + +def recursion_lock(retval, lock_name = "__recursion_lock__"): + def decorator(func): + def wrapper(self, *args, **kw): + if getattr(self, lock_name, False): + return retval + setattr(self, lock_name, True) + try: + return func(self, *args, **kw) + finally: + setattr(self, lock_name, False) + wrapper.__name__ = func.__name__ + return wrapper + return decorator + +class Container(MutableMapping): + """ + A generic container of attributes. + + Containers are the common way to express parsed data. + """ + + def __init__(self, **kw): + self.__dict__ = kw + + # The core dictionary interface. + + def __getitem__(self, name): + return self.__dict__[name] + + def __delitem__(self, name): + del self.__dict__[name] + + def __setitem__(self, name, value): + self.__dict__[name] = value + + def keys(self): + return self.__dict__.keys() + + def __len__(self): + return len(self.__dict__.keys()) + + # Extended dictionary interface. + + def update(self, other): + self.__dict__.update(other) + + __update__ = update + + def __contains__(self, value): + return value in self.__dict__ + + # Rich comparisons. + + def __eq__(self, other): + try: + return self.__dict__ == other.__dict__ + except AttributeError: + return False + + def __ne__(self, other): + return not self == other + + # Copy interface. + + def copy(self): + return self.__class__(**self.__dict__) + + __copy__ = copy + + # Iterator interface. + + def __iter__(self): + return iter(self.__dict__) + + def __repr__(self): + return "%s(%s)" % (self.__class__.__name__, repr(self.__dict__)) + + def __str__(self): + return "%s(%s)" % (self.__class__.__name__, str(self.__dict__)) + +class FlagsContainer(Container): + """ + A container providing pretty-printing for flags. + + Only set flags are displayed. + """ + + @recursion_lock("<...>") + def __str__(self): + d = dict((k, self[k]) for k in self + if self[k] and not k.startswith("_")) + return "%s(%s)" % (self.__class__.__name__, pformat(d)) + +class ListContainer(list): + """ + A container for lists. + """ + + __slots__ = ["__recursion_lock__"] + + @recursion_lock("[...]") + def __str__(self): + return pformat(self) + +class LazyContainer(object): + + __slots__ = ["subcon", "stream", "pos", "context", "_value"] + + def __init__(self, subcon, stream, pos, context): + self.subcon = subcon + self.stream = stream + self.pos = pos + self.context = context + self._value = NotImplemented + + def __eq__(self, other): + try: + return self._value == other._value + except AttributeError: + return False + + def __ne__(self, other): + return not (self == other) + + def __str__(self): + return self.__pretty_str__() + + def __pretty_str__(self, nesting = 1, indentation = " "): + if self._value is NotImplemented: + text = "" + elif hasattr(self._value, "__pretty_str__"): + text = self._value.__pretty_str__(nesting, indentation) + else: + text = str(self._value) + return "%s: %s" % (self.__class__.__name__, text) + + def read(self): + self.stream.seek(self.pos) + return self.subcon._parse(self.stream, self.context) + + def dispose(self): + self.subcon = None + self.stream = None + self.context = None + self.pos = None + + def _get_value(self): + if self._value is NotImplemented: + self._value = self.read() + return self._value + + value = property(_get_value) + + has_value = property(lambda self: self._value is not NotImplemented) diff --git a/tools/utils/contrib/elftools/construct/lib/hex.py b/tools/utils/contrib/elftools/construct/lib/hex.py new file mode 100755 index 0000000000..e378e228b7 --- /dev/null +++ b/tools/utils/contrib/elftools/construct/lib/hex.py @@ -0,0 +1,44 @@ +from .py3compat import byte2int, int2byte, bytes2str + + +# Map an integer in the inclusive range 0-255 to its string byte representation +_printable = dict((i, ".") for i in range(256)) +_printable.update((i, bytes2str(int2byte(i))) for i in range(32, 128)) + + +def hexdump(data, linesize): + """ + data is a bytes object. The returned result is a string. + """ + prettylines = [] + if len(data) < 65536: + fmt = "%%04X %%-%ds %%s" + else: + fmt = "%%08X %%-%ds %%s" + fmt = fmt % (3 * linesize - 1,) + for i in range(0, len(data), linesize): + line = data[i : i + linesize] + hextext = " ".join('%02x' % byte2int(b) for b in line) + rawtext = "".join(_printable[byte2int(b)] for b in line) + prettylines.append(fmt % (i, str(hextext), str(rawtext))) + return prettylines + + +class HexString(bytes): + """ + Represents bytes that will be hex-dumped to a string when its string + representation is requested. + """ + def __init__(self, data, linesize = 16): + self.linesize = linesize + + def __new__(cls, data, *args, **kwargs): + return bytes.__new__(cls, data) + + def __str__(self): + if not self: + return "''" + sep = "\n" + return sep + sep.join( + hexdump(self, self.linesize)) + diff --git a/tools/utils/contrib/elftools/construct/lib/py3compat.py b/tools/utils/contrib/elftools/construct/lib/py3compat.py new file mode 100755 index 0000000000..4a52c29305 --- /dev/null +++ b/tools/utils/contrib/elftools/construct/lib/py3compat.py @@ -0,0 +1,70 @@ +#------------------------------------------------------------------------------- +# py3compat.py +# +# Some Python2&3 compatibility code +#------------------------------------------------------------------------------- +import sys +PY3 = sys.version_info[0] == 3 + + +if PY3: + import io + StringIO = io.StringIO + BytesIO = io.BytesIO + + def bchr(i): + """ When iterating over b'...' in Python 2 you get single b'_' chars + and in Python 3 you get integers. Call bchr to always turn this + to single b'_' chars. + """ + return bytes((i,)) + + def u(s): + return s + + def int2byte(i): + return bytes((i,)) + + def byte2int(b): + return b + + def str2bytes(s): + return s.encode("latin-1") + + def str2unicode(s): + return s + + def bytes2str(b): + return b.decode('latin-1') + + def decodebytes(b, encoding): + return bytes(b, encoding) + + advance_iterator = next + +else: + import cStringIO + StringIO = BytesIO = cStringIO.StringIO + + int2byte = chr + byte2int = ord + bchr = lambda i: i + + def u(s): + return unicode(s, "unicode_escape") + + def str2bytes(s): + return s + + def str2unicode(s): + return unicode(s, "unicode_escape") + + def bytes2str(b): + return b + + def decodebytes(b, encoding): + return b.decode(encoding) + + def advance_iterator(it): + return it.next() + diff --git a/tools/utils/contrib/elftools/construct/macros.py b/tools/utils/contrib/elftools/construct/macros.py new file mode 100755 index 0000000000..5e893ddeb4 --- /dev/null +++ b/tools/utils/contrib/elftools/construct/macros.py @@ -0,0 +1,634 @@ +from .lib.py3compat import int2byte +from .lib import (BitStreamReader, BitStreamWriter, encode_bin, + decode_bin) +from .core import (Struct, MetaField, StaticField, FormatField, + OnDemand, Pointer, Switch, Value, RepeatUntil, MetaArray, Sequence, Range, + Select, Pass, SizeofError, Buffered, Restream, Reconfig) +from .adapters import (BitIntegerAdapter, PaddingAdapter, + ConstAdapter, CStringAdapter, LengthValueAdapter, IndexingAdapter, + PaddedStringAdapter, FlagsAdapter, StringAdapter, MappingAdapter) + + +#=============================================================================== +# fields +#=============================================================================== +def Field(name, length): + """ + A field consisting of a specified number of bytes. + + :param str name: the name of the field + :param length: the length of the field. the length can be either an integer + (StaticField), or a function that takes the context as an argument and + returns the length (MetaField) + """ + if callable(length): + return MetaField(name, length) + else: + return StaticField(name, length) + +def BitField(name, length, swapped = False, signed = False, bytesize = 8): + """ + BitFields, as the name suggests, are fields that operate on raw, unaligned + bits, and therefore must be enclosed in a BitStruct. Using them is very + similar to all normal fields: they take a name and a length (in bits). + + :param str name: name of the field + :param int length: number of bits in the field, or a function that takes + the context as its argument and returns the length + :param bool swapped: whether the value is byte-swapped + :param bool signed: whether the value is signed + :param int bytesize: number of bits per byte, for byte-swapping + + >>> foo = BitStruct("foo", + ... BitField("a", 3), + ... Flag("b"), + ... Padding(3), + ... Nibble("c"), + ... BitField("d", 5), + ... ) + >>> foo.parse("\\xe1\\x1f") + Container(a = 7, b = False, c = 8, d = 31) + >>> foo = BitStruct("foo", + ... BitField("a", 3), + ... Flag("b"), + ... Padding(3), + ... Nibble("c"), + ... Struct("bar", + ... Nibble("d"), + ... Bit("e"), + ... ) + ... ) + >>> foo.parse("\\xe1\\x1f") + Container(a = 7, b = False, bar = Container(d = 15, e = 1), c = 8) + """ + + return BitIntegerAdapter(Field(name, length), + length, + swapped=swapped, + signed=signed, + bytesize=bytesize + ) + +def Padding(length, pattern = "\x00", strict = False): + r"""a padding field (value is discarded) + * length - the length of the field. the length can be either an integer, + or a function that takes the context as an argument and returns the + length + * pattern - the padding pattern (character) to use. default is "\x00" + * strict - whether or not to raise an exception is the actual padding + pattern mismatches the desired pattern. default is False. + """ + return PaddingAdapter(Field(None, length), + pattern = pattern, + strict = strict, + ) + +def Flag(name, truth = 1, falsehood = 0, default = False): + """ + A flag. + + Flags are usually used to signify a Boolean value, and this construct + maps values onto the ``bool`` type. + + .. note:: This construct works with both bit and byte contexts. + + .. warning:: Flags default to False, not True. This is different from the + C and Python way of thinking about truth, and may be subject to change + in the future. + + :param str name: field name + :param int truth: value of truth (default 1) + :param int falsehood: value of falsehood (default 0) + :param bool default: default value (default False) + """ + + return SymmetricMapping(Field(name, 1), + {True : int2byte(truth), False : int2byte(falsehood)}, + default = default, + ) + +#=============================================================================== +# field shortcuts +#=============================================================================== +def Bit(name): + """a 1-bit BitField; must be enclosed in a BitStruct""" + return BitField(name, 1) +def Nibble(name): + """a 4-bit BitField; must be enclosed in a BitStruct""" + return BitField(name, 4) +def Octet(name): + """an 8-bit BitField; must be enclosed in a BitStruct""" + return BitField(name, 8) + +def UBInt8(name): + """unsigned, big endian 8-bit integer""" + return FormatField(name, ">", "B") +def UBInt16(name): + """unsigned, big endian 16-bit integer""" + return FormatField(name, ">", "H") +def UBInt32(name): + """unsigned, big endian 32-bit integer""" + return FormatField(name, ">", "L") +def UBInt64(name): + """unsigned, big endian 64-bit integer""" + return FormatField(name, ">", "Q") + +def SBInt8(name): + """signed, big endian 8-bit integer""" + return FormatField(name, ">", "b") +def SBInt16(name): + """signed, big endian 16-bit integer""" + return FormatField(name, ">", "h") +def SBInt32(name): + """signed, big endian 32-bit integer""" + return FormatField(name, ">", "l") +def SBInt64(name): + """signed, big endian 64-bit integer""" + return FormatField(name, ">", "q") + +def ULInt8(name): + """unsigned, little endian 8-bit integer""" + return FormatField(name, "<", "B") +def ULInt16(name): + """unsigned, little endian 16-bit integer""" + return FormatField(name, "<", "H") +def ULInt32(name): + """unsigned, little endian 32-bit integer""" + return FormatField(name, "<", "L") +def ULInt64(name): + """unsigned, little endian 64-bit integer""" + return FormatField(name, "<", "Q") + +def SLInt8(name): + """signed, little endian 8-bit integer""" + return FormatField(name, "<", "b") +def SLInt16(name): + """signed, little endian 16-bit integer""" + return FormatField(name, "<", "h") +def SLInt32(name): + """signed, little endian 32-bit integer""" + return FormatField(name, "<", "l") +def SLInt64(name): + """signed, little endian 64-bit integer""" + return FormatField(name, "<", "q") + +def UNInt8(name): + """unsigned, native endianity 8-bit integer""" + return FormatField(name, "=", "B") +def UNInt16(name): + """unsigned, native endianity 16-bit integer""" + return FormatField(name, "=", "H") +def UNInt32(name): + """unsigned, native endianity 32-bit integer""" + return FormatField(name, "=", "L") +def UNInt64(name): + """unsigned, native endianity 64-bit integer""" + return FormatField(name, "=", "Q") + +def SNInt8(name): + """signed, native endianity 8-bit integer""" + return FormatField(name, "=", "b") +def SNInt16(name): + """signed, native endianity 16-bit integer""" + return FormatField(name, "=", "h") +def SNInt32(name): + """signed, native endianity 32-bit integer""" + return FormatField(name, "=", "l") +def SNInt64(name): + """signed, native endianity 64-bit integer""" + return FormatField(name, "=", "q") + +def BFloat32(name): + """big endian, 32-bit IEEE floating point number""" + return FormatField(name, ">", "f") +def LFloat32(name): + """little endian, 32-bit IEEE floating point number""" + return FormatField(name, "<", "f") +def NFloat32(name): + """native endianity, 32-bit IEEE floating point number""" + return FormatField(name, "=", "f") + +def BFloat64(name): + """big endian, 64-bit IEEE floating point number""" + return FormatField(name, ">", "d") +def LFloat64(name): + """little endian, 64-bit IEEE floating point number""" + return FormatField(name, "<", "d") +def NFloat64(name): + """native endianity, 64-bit IEEE floating point number""" + return FormatField(name, "=", "d") + + +#=============================================================================== +# arrays +#=============================================================================== +def Array(count, subcon): + """ + Repeats the given unit a fixed number of times. + + :param int count: number of times to repeat + :param ``Construct`` subcon: construct to repeat + + >>> c = Array(4, UBInt8("foo")) + >>> c.parse("\\x01\\x02\\x03\\x04") + [1, 2, 3, 4] + >>> c.parse("\\x01\\x02\\x03\\x04\\x05\\x06") + [1, 2, 3, 4] + >>> c.build([5,6,7,8]) + '\\x05\\x06\\x07\\x08' + >>> c.build([5,6,7,8,9]) + Traceback (most recent call last): + ... + construct.core.RangeError: expected 4..4, found 5 + """ + + if callable(count): + con = MetaArray(count, subcon) + else: + con = MetaArray(lambda ctx: count, subcon) + con._clear_flag(con.FLAG_DYNAMIC) + return con + +def PrefixedArray(subcon, length_field = UBInt8("length")): + """an array prefixed by a length field. + * subcon - the subcon to be repeated + * length_field - a construct returning an integer + """ + return LengthValueAdapter( + Sequence(subcon.name, + length_field, + Array(lambda ctx: ctx[length_field.name], subcon), + nested = False + ) + ) + +def OpenRange(mincount, subcon): + from sys import maxsize + return Range(mincount, maxsize, subcon) + +def GreedyRange(subcon): + """ + Repeats the given unit one or more times. + + :param ``Construct`` subcon: construct to repeat + + >>> from construct import GreedyRange, UBInt8 + >>> c = GreedyRange(UBInt8("foo")) + >>> c.parse("\\x01") + [1] + >>> c.parse("\\x01\\x02\\x03") + [1, 2, 3] + >>> c.parse("\\x01\\x02\\x03\\x04\\x05\\x06") + [1, 2, 3, 4, 5, 6] + >>> c.parse("") + Traceback (most recent call last): + ... + construct.core.RangeError: expected 1..2147483647, found 0 + >>> c.build([1,2]) + '\\x01\\x02' + >>> c.build([]) + Traceback (most recent call last): + ... + construct.core.RangeError: expected 1..2147483647, found 0 + """ + + return OpenRange(1, subcon) + +def OptionalGreedyRange(subcon): + """ + Repeats the given unit zero or more times. This repeater can't + fail, as it accepts lists of any length. + + :param ``Construct`` subcon: construct to repeat + + >>> from construct import OptionalGreedyRange, UBInt8 + >>> c = OptionalGreedyRange(UBInt8("foo")) + >>> c.parse("") + [] + >>> c.parse("\\x01\\x02") + [1, 2] + >>> c.build([]) + '' + >>> c.build([1,2]) + '\\x01\\x02' + """ + + return OpenRange(0, subcon) + + +#=============================================================================== +# subconstructs +#=============================================================================== +def Optional(subcon): + """an optional construct. if parsing fails, returns None. + * subcon - the subcon to optionally parse or build + """ + return Select(subcon.name, subcon, Pass) + +def Bitwise(subcon): + """converts the stream to bits, and passes the bitstream to subcon + * subcon - a bitwise construct (usually BitField) + """ + # subcons larger than MAX_BUFFER will be wrapped by Restream instead + # of Buffered. implementation details, don't stick your nose in :) + MAX_BUFFER = 1024 * 8 + def resizer(length): + if length & 7: + raise SizeofError("size must be a multiple of 8", length) + return length >> 3 + if not subcon._is_flag(subcon.FLAG_DYNAMIC) and subcon.sizeof() < MAX_BUFFER: + con = Buffered(subcon, + encoder = decode_bin, + decoder = encode_bin, + resizer = resizer + ) + else: + con = Restream(subcon, + stream_reader = BitStreamReader, + stream_writer = BitStreamWriter, + resizer = resizer) + return con + +def Aligned(subcon, modulus = 4, pattern = "\x00"): + r"""aligns subcon to modulus boundary using padding pattern + * subcon - the subcon to align + * modulus - the modulus boundary (default is 4) + * pattern - the padding pattern (default is \x00) + """ + if modulus < 2: + raise ValueError("modulus must be >= 2", modulus) + def padlength(ctx): + return (modulus - (subcon._sizeof(ctx) % modulus)) % modulus + return SeqOfOne(subcon.name, + subcon, + # ?????? + # ?????? + # ?????? + # ?????? + Padding(padlength, pattern = pattern), + nested = False, + ) + +def SeqOfOne(name, *args, **kw): + """a sequence of one element. only the first element is meaningful, the + rest are discarded + * name - the name of the sequence + * args - subconstructs + * kw - any keyword arguments to Sequence + """ + return IndexingAdapter(Sequence(name, *args, **kw), index = 0) + +def Embedded(subcon): + """embeds a struct into the enclosing struct. + * subcon - the struct to embed + """ + return Reconfig(subcon.name, subcon, subcon.FLAG_EMBED) + +def Rename(newname, subcon): + """renames an existing construct + * newname - the new name + * subcon - the subcon to rename + """ + return Reconfig(newname, subcon) + +def Alias(newname, oldname): + """creates an alias for an existing element in a struct + * newname - the new name + * oldname - the name of an existing element + """ + return Value(newname, lambda ctx: ctx[oldname]) + + +#=============================================================================== +# mapping +#=============================================================================== +def SymmetricMapping(subcon, mapping, default = NotImplemented): + """defines a symmetrical mapping: a->b, b->a. + * subcon - the subcon to map + * mapping - the encoding mapping (a dict); the decoding mapping is + achieved by reversing this mapping + * default - the default value to use when no mapping is found. if no + default value is given, and exception is raised. setting to Pass would + return the value "as is" (unmapped) + """ + reversed_mapping = dict((v, k) for k, v in mapping.items()) + return MappingAdapter(subcon, + encoding = mapping, + decoding = reversed_mapping, + encdefault = default, + decdefault = default, + ) + +def Enum(subcon, **kw): + """a set of named values mapping. + * subcon - the subcon to map + * kw - keyword arguments which serve as the encoding mapping + * _default_ - an optional, keyword-only argument that specifies the + default value to use when the mapping is undefined. if not given, + and exception is raised when the mapping is undefined. use `Pass` to + pass the unmapped value as-is + """ + return SymmetricMapping(subcon, kw, kw.pop("_default_", NotImplemented)) + +def FlagsEnum(subcon, **kw): + """a set of flag values mapping. + * subcon - the subcon to map + * kw - keyword arguments which serve as the encoding mapping + """ + return FlagsAdapter(subcon, kw) + + +#=============================================================================== +# structs +#=============================================================================== +def AlignedStruct(name, *subcons, **kw): + """a struct of aligned fields + * name - the name of the struct + * subcons - the subcons that make up this structure + * kw - keyword arguments to pass to Aligned: 'modulus' and 'pattern' + """ + return Struct(name, *(Aligned(sc, **kw) for sc in subcons)) + +def BitStruct(name, *subcons): + """a struct of bitwise fields + * name - the name of the struct + * subcons - the subcons that make up this structure + """ + return Bitwise(Struct(name, *subcons)) + +def EmbeddedBitStruct(*subcons): + """an embedded BitStruct. no name is necessary. + * subcons - the subcons that make up this structure + """ + return Bitwise(Embedded(Struct(None, *subcons))) + +#=============================================================================== +# strings +#=============================================================================== +def String(name, length, encoding=None, padchar=None, paddir="right", + trimdir="right"): + """ + A configurable, fixed-length string field. + + The padding character must be specified for padding and trimming to work. + + :param str name: name + :param int length: length, in bytes + :param str encoding: encoding (e.g. "utf8") or None for no encoding + :param str padchar: optional character to pad out strings + :param str paddir: direction to pad out strings; one of "right", "left", + or "both" + :param str trim: direction to trim strings; one of "right", "left" + + >>> from construct import String + >>> String("foo", 5).parse("hello") + 'hello' + >>> + >>> String("foo", 12, encoding = "utf8").parse("hello joh\\xd4\\x83n") + u'hello joh\\u0503n' + >>> + >>> foo = String("foo", 10, padchar = "X", paddir = "right") + >>> foo.parse("helloXXXXX") + 'hello' + >>> foo.build("hello") + 'helloXXXXX' + """ + + con = StringAdapter(Field(name, length), encoding=encoding) + if padchar is not None: + con = PaddedStringAdapter(con, padchar=padchar, paddir=paddir, + trimdir=trimdir) + return con + +def PascalString(name, length_field=UBInt8("length"), encoding=None): + """ + A length-prefixed string. + + ``PascalString`` is named after the string types of Pascal, which are + length-prefixed. Lisp strings also follow this convention. + + The length field will appear in the same ``Container`` as the + ``PascalString``, with the given name. + + :param str name: name + :param ``Construct`` length_field: a field which will store the length of + the string + :param str encoding: encoding (e.g. "utf8") or None for no encoding + + >>> foo = PascalString("foo") + >>> foo.parse("\\x05hello") + 'hello' + >>> foo.build("hello world") + '\\x0bhello world' + >>> + >>> foo = PascalString("foo", length_field = UBInt16("length")) + >>> foo.parse("\\x00\\x05hello") + 'hello' + >>> foo.build("hello") + '\\x00\\x05hello' + """ + + return StringAdapter( + LengthValueAdapter( + Sequence(name, + length_field, + Field("data", lambda ctx: ctx[length_field.name]), + ) + ), + encoding=encoding, + ) + +def CString(name, terminators=b"\x00", encoding=None, + char_field=Field(None, 1)): + """ + A string ending in a terminator. + + ``CString`` is similar to the strings of C, C++, and other related + programming languages. + + By default, the terminator is the NULL byte (b``0x00``). + + :param str name: name + :param iterable terminators: sequence of valid terminators, in order of + preference + :param str encoding: encoding (e.g. "utf8") or None for no encoding + :param ``Construct`` char_field: construct representing a single character + + >>> foo = CString("foo") + >>> foo.parse(b"hello\\x00") + b'hello' + >>> foo.build(b"hello") + b'hello\\x00' + >>> foo = CString("foo", terminators = b"XYZ") + >>> foo.parse(b"helloX") + b'hello' + >>> foo.parse(b"helloY") + b'hello' + >>> foo.parse(b"helloZ") + b'hello' + >>> foo.build(b"hello") + b'helloX' + """ + + return Rename(name, + CStringAdapter( + RepeatUntil(lambda obj, ctx: obj in terminators, char_field), + terminators=terminators, + encoding=encoding, + ) + ) + + +#=============================================================================== +# conditional +#=============================================================================== +def IfThenElse(name, predicate, then_subcon, else_subcon): + """an if-then-else conditional construct: if the predicate indicates True, + `then_subcon` will be used; otherwise `else_subcon` + * name - the name of the construct + * predicate - a function taking the context as an argument and returning + True or False + * then_subcon - the subcon that will be used if the predicate returns True + * else_subcon - the subcon that will be used if the predicate returns False + """ + return Switch(name, lambda ctx: bool(predicate(ctx)), + { + True : then_subcon, + False : else_subcon, + } + ) + +def If(predicate, subcon, elsevalue = None): + """an if-then conditional construct: if the predicate indicates True, + subcon will be used; otherwise, `elsevalue` will be returned instead. + * predicate - a function taking the context as an argument and returning + True or False + * subcon - the subcon that will be used if the predicate returns True + * elsevalue - the value that will be used should the predicate return False. + by default this value is None. + """ + return IfThenElse(subcon.name, + predicate, + subcon, + Value("elsevalue", lambda ctx: elsevalue) + ) + + +#=============================================================================== +# misc +#=============================================================================== +def OnDemandPointer(offsetfunc, subcon, force_build = True): + """an on-demand pointer. + * offsetfunc - a function taking the context as an argument and returning + the absolute stream position + * subcon - the subcon that will be parsed from the `offsetfunc()` stream + position on demand + * force_build - see OnDemand. by default True. + """ + return OnDemand(Pointer(offsetfunc, subcon), + advance_stream = False, + force_build = force_build + ) + +def Magic(data): + return ConstAdapter(Field(None, len(data)), data) diff --git a/tools/utils/contrib/elftools/dwarf/__init__.py b/tools/utils/contrib/elftools/dwarf/__init__.py new file mode 100755 index 0000000000..e69de29bb2 diff --git a/tools/utils/contrib/elftools/dwarf/abbrevtable.py b/tools/utils/contrib/elftools/dwarf/abbrevtable.py new file mode 100755 index 0000000000..44ccdd5e5a --- /dev/null +++ b/tools/utils/contrib/elftools/dwarf/abbrevtable.py @@ -0,0 +1,80 @@ +#------------------------------------------------------------------------------- +# elftools: dwarf/abbrevtable.py +# +# DWARF abbreviation table +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +from ..common.utils import struct_parse, dwarf_assert + + +class AbbrevTable(object): + """ Represents a DWARF abbreviation table. + """ + def __init__(self, structs, stream, offset): + """ Create new abbreviation table. Parses the actual table from the + stream and stores it internally. + + structs: + A DWARFStructs instance for parsing the data + + stream, offset: + The stream and offset into the stream where this abbreviation + table lives. + """ + self.structs = structs + self.stream = stream + self.offset = offset + + self._abbrev_map = self._parse_abbrev_table() + + def get_abbrev(self, code): + """ Get the AbbrevDecl for a given code. Raise KeyError if no + declaration for this code exists. + """ + return AbbrevDecl(code, self._abbrev_map[code]) + + def _parse_abbrev_table(self): + """ Parse the abbrev table from the stream + """ + map = {} + self.stream.seek(self.offset) + while True: + decl_code = struct_parse( + struct=self.structs.Dwarf_uleb128(''), + stream=self.stream) + if decl_code == 0: + break + declaration = struct_parse( + struct=self.structs.Dwarf_abbrev_declaration, + stream=self.stream) + map[decl_code] = declaration + return map + + +class AbbrevDecl(object): + """ Wraps a parsed abbreviation declaration, exposing its fields with + dict-like access, and adding some convenience methods. + + The abbreviation declaration represents an "entry" that points to it. + """ + def __init__(self, code, decl): + self.code = code + self.decl = decl + + def has_children(self): + """ Does the entry have children? + """ + return self['children_flag'] == 'DW_CHILDREN_yes' + + def iter_attr_specs(self): + """ Iterate over the attribute specifications for the entry. Yield + (name, form) pairs. + """ + for attr_spec in self['attr_spec']: + yield attr_spec.name, attr_spec.form + + def __getitem__(self, entry): + return self.decl[entry] + diff --git a/tools/utils/contrib/elftools/dwarf/callframe.py b/tools/utils/contrib/elftools/dwarf/callframe.py new file mode 100755 index 0000000000..22f6a71041 --- /dev/null +++ b/tools/utils/contrib/elftools/dwarf/callframe.py @@ -0,0 +1,451 @@ +#------------------------------------------------------------------------------- +# elftools: dwarf/callframe.py +# +# DWARF call frame information +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +import copy +from collections import namedtuple +from ..common.utils import (struct_parse, dwarf_assert, preserve_stream_pos) +from ..common.py3compat import iterkeys +from .structs import DWARFStructs +from .constants import * + + +class CallFrameInfo(object): + """ DWARF CFI (Call Frame Info) + + stream, size: + A stream holding the .debug_frame section, and the size of the + section in it. + + base_structs: + The structs to be used as the base for parsing this section. + Eventually, each entry gets its own structs based on the initial + length field it starts with. The address_size, however, is taken + from base_structs. This appears to be a limitation of the DWARFv3 + standard, fixed in v4. + A discussion I had on dwarf-discuss confirms this. + So for DWARFv4 we'll take the address size from the CIE header, + but for earlier versions will use the elfclass of the containing + file; more sophisticated methods are used by libdwarf and others, + such as guessing which CU contains which FDEs (based on their + address ranges) and taking the address_size from those CUs. + """ + def __init__(self, stream, size, base_structs): + self.stream = stream + self.size = size + self.base_structs = base_structs + self.entries = None + + # Map between an offset in the stream and the entry object found at this + # offset. Useful for assigning CIE to FDEs according to the CIE_pointer + # header field which contains a stream offset. + self._entry_cache = {} + + def get_entries(self): + """ Get a list of entries that constitute this CFI. The list consists + of CIE or FDE objects, in the order of their appearance in the + section. + """ + if self.entries is None: + self.entries = self._parse_entries() + return self.entries + + #------------------------- + + def _parse_entries(self): + entries = [] + offset = 0 + while offset < self.size: + entries.append(self._parse_entry_at(offset)) + offset = self.stream.tell() + return entries + + def _parse_entry_at(self, offset): + """ Parse an entry from self.stream starting with the given offset. + Return the entry object. self.stream will point right after the + entry. + """ + if offset in self._entry_cache: + return self._entry_cache[offset] + + entry_length = struct_parse( + self.base_structs.Dwarf_uint32(''), self.stream, offset) + dwarf_format = 64 if entry_length == 0xFFFFFFFF else 32 + + entry_structs = DWARFStructs( + little_endian=self.base_structs.little_endian, + dwarf_format=dwarf_format, + address_size=self.base_structs.address_size) + + # Read the next field to see whether this is a CIE or FDE + CIE_id = struct_parse( + entry_structs.Dwarf_offset(''), self.stream) + + is_CIE = ( + (dwarf_format == 32 and CIE_id == 0xFFFFFFFF) or + CIE_id == 0xFFFFFFFFFFFFFFFF) + + if is_CIE: + header_struct = entry_structs.Dwarf_CIE_header + else: + header_struct = entry_structs.Dwarf_FDE_header + + # Parse the header, which goes up to and including the + # return_address_register field + header = struct_parse( + header_struct, self.stream, offset) + + # If this is DWARF version 4 or later, we can have a more precise + # address size, read from the CIE header. + if entry_structs.dwarf_version >= 4: + entry_structs = DWARFStructs( + little_endian=entry_structs.little_endian, + dwarf_format=entry_structs.dwarf_format, + address_size=header.address_size) + + # For convenience, compute the end offset for this entry + end_offset = ( + offset + header.length + + entry_structs.initial_length_field_size()) + + # At this point self.stream is at the start of the instruction list + # for this entry + instructions = self._parse_instructions( + entry_structs, self.stream.tell(), end_offset) + + if is_CIE: + self._entry_cache[offset] = CIE( + header=header, instructions=instructions, offset=offset, + structs=entry_structs) + else: # FDE + with preserve_stream_pos(self.stream): + cie = self._parse_entry_at(header['CIE_pointer']) + self._entry_cache[offset] = FDE( + header=header, instructions=instructions, offset=offset, + structs=entry_structs, cie=cie) + return self._entry_cache[offset] + + def _parse_instructions(self, structs, offset, end_offset): + """ Parse a list of CFI instructions from self.stream, starting with + the offset and until (not including) end_offset. + Return a list of CallFrameInstruction objects. + """ + instructions = [] + while offset < end_offset: + opcode = struct_parse(structs.Dwarf_uint8(''), self.stream, offset) + args = [] + + primary = opcode & _PRIMARY_MASK + primary_arg = opcode & _PRIMARY_ARG_MASK + if primary == DW_CFA_advance_loc: + args = [primary_arg] + elif primary == DW_CFA_offset: + args = [ + primary_arg, + struct_parse(structs.Dwarf_uleb128(''), self.stream)] + elif primary == DW_CFA_restore: + args = [primary_arg] + # primary == 0 and real opcode is extended + elif opcode in (DW_CFA_nop, DW_CFA_remember_state, + DW_CFA_restore_state): + args = [] + elif opcode == DW_CFA_set_loc: + args = [ + struct_parse(structs.Dwarf_target_addr(''), self.stream)] + elif opcode == DW_CFA_advance_loc1: + args = [struct_parse(structs.Dwarf_uint8(''), self.stream)] + elif opcode == DW_CFA_advance_loc2: + args = [struct_parse(structs.Dwarf_uint16(''), self.stream)] + elif opcode == DW_CFA_advance_loc4: + args = [struct_parse(structs.Dwarf_uint32(''), self.stream)] + elif opcode in (DW_CFA_offset_extended, DW_CFA_register, + DW_CFA_def_cfa, DW_CFA_val_offset): + args = [ + struct_parse(structs.Dwarf_uleb128(''), self.stream), + struct_parse(structs.Dwarf_uleb128(''), self.stream)] + elif opcode in (DW_CFA_restore_extended, DW_CFA_undefined, + DW_CFA_same_value, DW_CFA_def_cfa_register, + DW_CFA_def_cfa_offset): + args = [struct_parse(structs.Dwarf_uleb128(''), self.stream)] + elif opcode == DW_CFA_def_cfa_offset_sf: + args = [struct_parse(structs.Dwarf_sleb128(''), self.stream)] + elif opcode == DW_CFA_def_cfa_expression: + args = [struct_parse( + structs.Dwarf_dw_form['DW_FORM_block'], self.stream)] + elif opcode in (DW_CFA_expression, DW_CFA_val_expression): + args = [ + struct_parse(structs.Dwarf_uleb128(''), self.stream), + struct_parse( + structs.Dwarf_dw_form['DW_FORM_block'], self.stream)] + elif opcode in (DW_CFA_offset_extended_sf, + DW_CFA_def_cfa_sf, DW_CFA_val_offset_sf): + args = [ + struct_parse(structs.Dwarf_uleb128(''), self.stream), + struct_parse(structs.Dwarf_sleb128(''), self.stream)] + else: + dwarf_assert(False, 'Unknown CFI opcode: 0x%x' % opcode) + + instructions.append(CallFrameInstruction(opcode=opcode, args=args)) + offset = self.stream.tell() + return instructions + + +def instruction_name(opcode): + """ Given an opcode, return the instruction name. + """ + primary = opcode & _PRIMARY_MASK + if primary == 0: + return _OPCODE_NAME_MAP[opcode] + else: + return _OPCODE_NAME_MAP[primary] + + +class CallFrameInstruction(object): + """ An instruction in the CFI section. opcode is the instruction + opcode, numeric - as it appears in the section. args is a list of + arguments (including arguments embedded in the low bits of some + instructions, when applicable), decoded from the stream. + """ + def __init__(self, opcode, args): + self.opcode = opcode + self.args = args + + def __repr__(self): + return '%s (0x%x): %s' % ( + instruction_name(self.opcode), self.opcode, self.args) + + +class CFIEntry(object): + """ A common base class for CFI entries. + Contains a header and a list of instructions (CallFrameInstruction). + offset: the offset of this entry from the beginning of the section + cie: for FDEs, a CIE pointer is required + """ + def __init__(self, header, structs, instructions, offset, cie=None): + self.header = header + self.structs = structs + self.instructions = instructions + self.offset = offset + self.cie = cie + self._decoded_table = None + + def get_decoded(self): + """ Decode the CFI contained in this entry and return a + DecodedCallFrameTable object representing it. See the documentation + of that class to understand how to interpret the decoded table. + """ + if self._decoded_table is None: + self._decoded_table = self._decode_CFI_table() + return self._decoded_table + + def __getitem__(self, name): + """ Implement dict-like access to header entries + """ + return self.header[name] + + def _decode_CFI_table(self): + """ Decode the instructions contained in the given CFI entry and return + a DecodedCallFrameTable. + """ + if isinstance(self, CIE): + # For a CIE, initialize cur_line to an "empty" line + cie = self + cur_line = dict(pc=0, cfa=None) + reg_order = [] + else: # FDE + # For a FDE, we need to decode the attached CIE first, because its + # decoded table is needed. Its "initial instructions" describe a + # line that serves as the base (first) line in the FDE's table. + cie = self.cie + cie_decoded_table = cie.get_decoded() + last_line_in_CIE = copy.copy(cie_decoded_table.table[-1]) + cur_line = copy.copy(last_line_in_CIE) + cur_line['pc'] = self['initial_location'] + reg_order = copy.copy(cie_decoded_table.reg_order) + + table = [] + + # Keeps a stack for the use of DW_CFA_{remember|restore}_state + # instructions. + line_stack = [] + + def _add_to_order(regnum): + if regnum not in cur_line: + reg_order.append(regnum) + + for instr in self.instructions: + # Throughout this loop, cur_line is the current line. Some + # instructions add it to the table, but most instructions just + # update it without adding it to the table. + + name = instruction_name(instr.opcode) + + if name == 'DW_CFA_set_loc': + table.append(copy.copy(cur_line)) + cur_line['pc'] = instr.args[0] + elif name in ( 'DW_CFA_advance_loc1', 'DW_CFA_advance_loc2', + 'DW_CFA_advance_loc4', 'DW_CFA_advance_loc'): + table.append(copy.copy(cur_line)) + cur_line['pc'] += instr.args[0] * cie['code_alignment_factor'] + elif name == 'DW_CFA_def_cfa': + cur_line['cfa'] = CFARule( + reg=instr.args[0], + offset=instr.args[1]) + elif name == 'DW_CFA_def_cfa_sf': + cur_line['cfa'] = CFARule( + reg=instr.args[0], + offset=instr.args[1] * cie['code_alignment_factor']) + elif name == 'DW_CFA_def_cfa_register': + cur_line['cfa'] = CFARule( + reg=instr.args[0], + offset=cur_line['cfa'].offset) + elif name == 'DW_CFA_def_cfa_offset': + cur_line['cfa'] = CFARule( + reg=cur_line['cfa'].reg, + offset=instr.args[0]) + elif name == 'DW_CFA_def_cfa_expression': + cur_line['cfa'] = CFARule(expr=instr.args[0]) + elif name == 'DW_CFA_undefined': + _add_to_order(instr.args[0]) + cur_line[instr.args[0]] = RegisterRule(RegisterRule.UNDEFINED) + elif name == 'DW_CFA_same_value': + _add_to_order(instr.args[0]) + cur_line[instr.args[0]] = RegisterRule(RegisterRule.SAME_VALUE) + elif name in ( 'DW_CFA_offset', 'DW_CFA_offset_extended', + 'DW_CFA_offset_extended_sf'): + _add_to_order(instr.args[0]) + cur_line[instr.args[0]] = RegisterRule( + RegisterRule.OFFSET, + instr.args[1] * cie['data_alignment_factor']) + elif name in ('DW_CFA_val_offset', 'DW_CFA_val_offset_sf'): + _add_to_order(instr.args[0]) + cur_line[instr.args[0]] = RegisterRule( + RegisterRule.VAL_OFFSET, + instr.args[1] * cie['data_alignment_factor']) + elif name == 'DW_CFA_register': + _add_to_order(instr.args[0]) + cur_line[instr.args[0]] = RegisterRule( + RegisterRule.REGISTER, + instr.args[1]) + elif name == 'DW_CFA_expression': + _add_to_order(instr.args[0]) + cur_line[instr.args[0]] = RegisterRule( + RegisterRule.EXPRESSION, + instr.args[1]) + elif name == 'DW_CFA_val_expression': + _add_to_order(instr.args[0]) + cur_line[instr.args[0]] = RegisterRule( + RegisterRule.VAL_EXPRESSION, + instr.args[1]) + elif name in ('DW_CFA_restore', 'DW_CFA_restore_extended'): + _add_to_order(instr.args[0]) + dwarf_assert( + isinstance(self, FDE), + '%s instruction must be in a FDE' % name) + if instr.args[0] in last_line_in_CIE: + cur_line[instr.args[0]] = last_line_in_CIE[instr.args[0]] + else: + cur_line.pop(instr.args[0], None) + elif name == 'DW_CFA_remember_state': + line_stack.append(cur_line) + elif name == 'DW_CFA_restore_state': + cur_line = line_stack.pop() + + # The current line is appended to the table after all instructions + # have ended, in any case (even if there were no instructions). + table.append(cur_line) + return DecodedCallFrameTable(table=table, reg_order=reg_order) + + +# A CIE and FDE have exactly the same functionality, except that a FDE has +# a pointer to its CIE. The functionality was wholly encapsulated in CFIEntry, +# so the CIE and FDE classes exists separately for identification (instead +# of having an explicit "entry_type" field in CFIEntry). +# +class CIE(CFIEntry): + pass + + +class FDE(CFIEntry): + pass + + +class RegisterRule(object): + """ Register rules are used to find registers in call frames. Each rule + consists of a type (enumeration following DWARFv3 section 6.4.1) + and an optional argument to augment the type. + """ + UNDEFINED = 'UNDEFINED' + SAME_VALUE = 'SAME_VALUE' + OFFSET = 'OFFSET' + VAL_OFFSET = 'VAL_OFFSET' + REGISTER = 'REGISTER' + EXPRESSION = 'EXPRESSION' + VAL_EXPRESSION = 'VAL_EXPRESSION' + ARCHITECTURAL = 'ARCHITECTURAL' + + def __init__(self, type, arg=None): + self.type = type + self.arg = arg + + def __repr__(self): + return 'RegisterRule(%s, %s)' % (self.type, self.arg) + + +class CFARule(object): + """ A CFA rule is used to compute the CFA for each location. It either + consists of a register+offset, or a DWARF expression. + """ + def __init__(self, reg=None, offset=None, expr=None): + self.reg = reg + self.offset = offset + self.expr = expr + + def __repr__(self): + return 'CFARule(reg=%s, offset=%s, expr=%s)' % ( + self.reg, self.offset, self.expr) + + +# Represents the decoded CFI for an entry, which is just a large table, +# according to DWARFv3 section 6.4.1 +# +# DecodedCallFrameTable is a simple named tuple to group together the table +# and the register appearance order. +# +# table: +# +# A list of dicts that represent "lines" in the decoded table. Each line has +# some special dict entries: 'pc' for the location/program counter (LOC), +# and 'cfa' for the CFARule to locate the CFA on that line. +# The other entries are keyed by register numbers with RegisterRule values, +# and describe the rules for these registers. +# +# reg_order: +# +# A list of register numbers that are described in the table by the order of +# their appearance. +# +DecodedCallFrameTable = namedtuple( + 'DecodedCallFrameTable', 'table reg_order') + + +#---------------- PRIVATE ----------------# + +_PRIMARY_MASK = 0b11000000 +_PRIMARY_ARG_MASK = 0b00111111 + +# This dictionary is filled by automatically scanning the constants module +# for DW_CFA_* instructions, and mapping their values to names. Since all +# names were imported from constants with `import *`, we look in globals() +_OPCODE_NAME_MAP = {} +for name in list(iterkeys(globals())): + if name.startswith('DW_CFA'): + _OPCODE_NAME_MAP[globals()[name]] = name + + + + diff --git a/tools/utils/contrib/elftools/dwarf/compileunit.py b/tools/utils/contrib/elftools/dwarf/compileunit.py new file mode 100755 index 0000000000..f5011dde83 --- /dev/null +++ b/tools/utils/contrib/elftools/dwarf/compileunit.py @@ -0,0 +1,153 @@ +#------------------------------------------------------------------------------- +# elftools: dwarf/compileunit.py +# +# DWARF compile unit +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +from .die import DIE + + +class CompileUnit(object): + """ A DWARF compilation unit (CU). + + A normal compilation unit typically represents the text and data + contributed to an executable by a single relocatable object file. + It may be derived from several source files, + including pre-processed "include files" + + Serves as a container and context to DIEs that describe objects and code + belonging to a compilation unit. + + CU header entries can be accessed as dict keys from this object, i.e. + cu = CompileUnit(...) + cu['version'] # version field of the CU header + + To get the top-level DIE describing the compilation unit, call the + get_top_DIE method. + """ + def __init__(self, header, dwarfinfo, structs, cu_offset, cu_die_offset): + """ header: + CU header for this compile unit + + dwarfinfo: + The DWARFInfo context object which created this one + + structs: + A DWARFStructs instance suitable for this compile unit + + cu_offset: + Offset in the stream to the beginning of this CU (its header) + + cu_die_offset: + Offset in the stream of the top DIE of this CU + """ + self.dwarfinfo = dwarfinfo + self.header = header + self.structs = structs + self.cu_offset = cu_offset + self.cu_die_offset = cu_die_offset + + # The abbreviation table for this CU. Filled lazily when DIEs are + # requested. + self._abbrev_table = None + + # A list of DIEs belonging to this CU. Lazily parsed. + self._dielist = [] + + def dwarf_format(self): + """ Get the DWARF format (32 or 64) for this CU + """ + return self.structs.dwarf_format + + def get_abbrev_table(self): + """ Get the abbreviation table (AbbrevTable object) for this CU + """ + if self._abbrev_table is None: + self._abbrev_table = self.dwarfinfo.get_abbrev_table( + self['debug_abbrev_offset']) + return self._abbrev_table + + def get_top_DIE(self): + """ Get the top DIE (which is either a DW_TAG_compile_unit or + DW_TAG_partial_unit) of this CU + """ + return self._get_DIE(0) + + def iter_DIEs(self): + """ Iterate over all the DIEs in the CU, in order of their appearance. + Note that null DIEs will also be returned. + """ + self._parse_DIEs() + return iter(self._dielist) + + #------ PRIVATE ------# + + def __getitem__(self, name): + """ Implement dict-like access to header entries + """ + return self.header[name] + + def _get_DIE(self, index): + """ Get the DIE at the given index + """ + self._parse_DIEs() + return self._dielist[index] + + def _parse_DIEs(self): + """ Parse all the DIEs pertaining to this CU from the stream and shove + them sequentially into self._dielist. + Also set the child/sibling/parent links in the DIEs according + (unflattening the prefix-order of the DIE tree). + """ + if len(self._dielist) > 0: + return + + # Compute the boundary (one byte past the bounds) of this CU in the + # stream + cu_boundary = ( self.cu_offset + + self['unit_length'] + + self.structs.initial_length_field_size()) + + # First pass: parse all DIEs and place them into self._dielist + die_offset = self.cu_die_offset + while die_offset < cu_boundary: + die = DIE( + cu=self, + stream=self.dwarfinfo.debug_info_sec.stream, + offset=die_offset) + self._dielist.append(die) + die_offset += die.size + + # Second pass - unflatten the DIE tree + self._unflatten_tree() + + def _unflatten_tree(self): + """ "Unflatten" the DIE tree from it serial representation, by setting + the child/sibling/parent links of DIEs. + + Assumes self._dielist was already populated by a linear list of DIEs + read from the stream section + """ + # the first DIE in the list is the root node + root = self._dielist[0] + parentstack = [root] + + for die in self._dielist[1:]: + if not die.is_null(): + cur_parent = parentstack[-1] + # This DIE is a child of the current parent + cur_parent.add_child(die) + die.set_parent(cur_parent) + if die.has_children: + parentstack.append(die) + else: + # parentstack should not be really empty here. However, some + # compilers generate DWARF that has extra NULLs in the end and + # we don't want pyelftools to fail parsing them just because of + # this. + if len(parentstack) > 0: + # end of children for the current parent + parentstack.pop() + diff --git a/tools/utils/contrib/elftools/dwarf/constants.py b/tools/utils/contrib/elftools/dwarf/constants.py new file mode 100755 index 0000000000..bed25231f6 --- /dev/null +++ b/tools/utils/contrib/elftools/dwarf/constants.py @@ -0,0 +1,177 @@ +#------------------------------------------------------------------------------- +# elftools: dwarf/constants.py +# +# Constants and flags +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- + +# Inline codes +# +DW_INL_not_inlined = 0 +DW_INL_inlined = 1 +DW_INL_declared_not_inlined = 2 +DW_INL_declared_inlined = 3 + + +# Source languages +# +DW_LANG_C89 = 0x0001 +DW_LANG_C = 0x0002 +DW_LANG_Ada83 = 0x0003 +DW_LANG_C_plus_plus = 0x0004 +DW_LANG_Cobol74 = 0x0005 +DW_LANG_Cobol85 = 0x0006 +DW_LANG_Fortran77 = 0x0007 +DW_LANG_Fortran90 = 0x0008 +DW_LANG_Pascal83 = 0x0009 +DW_LANG_Modula2 = 0x000a +DW_LANG_Java = 0x000b +DW_LANG_C99 = 0x000c +DW_LANG_Ada95 = 0x000d +DW_LANG_Fortran95 = 0x000e +DW_LANG_PLI = 0x000f +DW_LANG_ObjC = 0x0010 +DW_LANG_ObjC_plus_plus = 0x0011 +DW_LANG_UPC = 0x0012 +DW_LANG_D = 0x0013 +DW_LANG_Python = 0x0014 +DW_LANG_Mips_Assembler = 0x8001 +DW_LANG_Upc = 0x8765 +DW_LANG_HP_Bliss = 0x8003 +DW_LANG_HP_Basic91 = 0x8004 +DW_LANG_HP_Pascal91 = 0x8005 +DW_LANG_HP_IMacro = 0x8006 +DW_LANG_HP_Assembler = 0x8007 + + +# Encoding +# +DW_ATE_void = 0x0 +DW_ATE_address = 0x1 +DW_ATE_boolean = 0x2 +DW_ATE_complex_float = 0x3 +DW_ATE_float = 0x4 +DW_ATE_signed = 0x5 +DW_ATE_signed_char = 0x6 +DW_ATE_unsigned = 0x7 +DW_ATE_unsigned_char = 0x8 +DW_ATE_imaginary_float = 0x9 +DW_ATE_packed_decimal = 0xa +DW_ATE_numeric_string = 0xb +DW_ATE_edited = 0xc +DW_ATE_signed_fixed = 0xd +DW_ATE_unsigned_fixed = 0xe +DW_ATE_decimal_float = 0xf +DW_ATE_UTF = 0x10 +DW_ATE_lo_user = 0x80 +DW_ATE_hi_user = 0xff +DW_ATE_HP_float80 = 0x80 +DW_ATE_HP_complex_float80 = 0x81 +DW_ATE_HP_float128 = 0x82 +DW_ATE_HP_complex_float128 = 0x83 +DW_ATE_HP_floathpintel = 0x84 +DW_ATE_HP_imaginary_float80 = 0x85 +DW_ATE_HP_imaginary_float128 = 0x86 + + +# Access +# +DW_ACCESS_public = 1 +DW_ACCESS_protected = 2 +DW_ACCESS_private = 3 + + +# Visibility +# +DW_VIS_local = 1 +DW_VIS_exported = 2 +DW_VIS_qualified = 3 + + +# Virtuality +# +DW_VIRTUALITY_none = 0 +DW_VIRTUALITY_virtual = 1 +DW_VIRTUALITY_pure_virtual = 2 + + +# ID case +# +DW_ID_case_sensitive = 0 +DW_ID_up_case = 1 +DW_ID_down_case = 2 +DW_ID_case_insensitive = 3 + + +# Calling convention +# +DW_CC_normal = 0x1 +DW_CC_program = 0x2 +DW_CC_nocall = 0x3 + + +# Ordering +# +DW_ORD_row_major = 0 +DW_ORD_col_major = 1 + + +# Line program opcodes +# +DW_LNS_copy = 0x01 +DW_LNS_advance_pc = 0x02 +DW_LNS_advance_line = 0x03 +DW_LNS_set_file = 0x04 +DW_LNS_set_column = 0x05 +DW_LNS_negate_stmt = 0x06 +DW_LNS_set_basic_block = 0x07 +DW_LNS_const_add_pc = 0x08 +DW_LNS_fixed_advance_pc = 0x09 +DW_LNS_set_prologue_end = 0x0a +DW_LNS_set_epilogue_begin = 0x0b +DW_LNS_set_isa = 0x0c +DW_LNE_end_sequence = 0x01 +DW_LNE_set_address = 0x02 +DW_LNE_define_file = 0x03 + + +# Call frame instructions +# +# Note that the first 3 instructions have the so-called "primary opcode" +# (as described in DWARFv3 7.23), so only their highest 2 bits take part +# in the opcode decoding. They are kept as constants with the low bits masked +# out, and the callframe module knows how to handle this. +# The other instructions use an "extended opcode" encoded just in the low 6 +# bits, with the high 2 bits, so these constants are exactly as they would +# appear in an actual file. +# +DW_CFA_advance_loc = 0b01000000 +DW_CFA_offset = 0b10000000 +DW_CFA_restore = 0b11000000 +DW_CFA_nop = 0x00 +DW_CFA_set_loc = 0x01 +DW_CFA_advance_loc1 = 0x02 +DW_CFA_advance_loc2 = 0x03 +DW_CFA_advance_loc4 = 0x04 +DW_CFA_offset_extended = 0x05 +DW_CFA_restore_extended = 0x06 +DW_CFA_undefined = 0x07 +DW_CFA_same_value = 0x08 +DW_CFA_register = 0x09 +DW_CFA_remember_state = 0x0a +DW_CFA_restore_state = 0x0b +DW_CFA_def_cfa = 0x0c +DW_CFA_def_cfa_register = 0x0d +DW_CFA_def_cfa_offset = 0x0e +DW_CFA_def_cfa_expression = 0x0f +DW_CFA_expression = 0x10 +DW_CFA_offset_extended_sf = 0x11 +DW_CFA_def_cfa_sf = 0x12 +DW_CFA_def_cfa_offset_sf = 0x13 +DW_CFA_val_offset = 0x14 +DW_CFA_val_offset_sf = 0x15 +DW_CFA_val_expression = 0x16 + + diff --git a/tools/utils/contrib/elftools/dwarf/descriptions.py b/tools/utils/contrib/elftools/dwarf/descriptions.py new file mode 100755 index 0000000000..ac8f772c8d --- /dev/null +++ b/tools/utils/contrib/elftools/dwarf/descriptions.py @@ -0,0 +1,548 @@ +#------------------------------------------------------------------------------- +# elftools: dwarf/descriptions.py +# +# Textual descriptions of the various values and enums of DWARF +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +from collections import defaultdict + +from .constants import * +from .dwarf_expr import GenericExprVisitor +from .die import DIE +from ..common.utils import preserve_stream_pos, dwarf_assert +from ..common.py3compat import bytes2str +from .callframe import instruction_name, CIE, FDE + + +def set_global_machine_arch(machine_arch): + global _MACHINE_ARCH + _MACHINE_ARCH = machine_arch + + +def describe_attr_value(attr, die, section_offset): + """ Given an attribute attr, return the textual representation of its + value, suitable for tools like readelf. + + To cover all cases, this function needs some extra arguments: + + die: the DIE this attribute was extracted from + section_offset: offset in the stream of the section the DIE belongs to + """ + descr_func = _ATTR_DESCRIPTION_MAP[attr.form] + val_description = descr_func(attr, die, section_offset) + + # For some attributes we can display further information + extra_info_func = _EXTRA_INFO_DESCRIPTION_MAP[attr.name] + extra_info = extra_info_func(attr, die, section_offset) + return str(val_description) + '\t' + extra_info + + +def describe_CFI_instructions(entry): + """ Given a CFI entry (CIE or FDE), return the textual description of its + instructions. + """ + def _assert_FDE_instruction(instr): + dwarf_assert( + isinstance(entry, FDE), + 'Unexpected instruction "%s" for a CIE' % instr) + + def _full_reg_name(regnum): + regname = describe_reg_name(regnum, _MACHINE_ARCH, False) + if regname: + return 'r%s (%s)' % (regnum, regname) + else: + return 'r%s' % regnum + + if isinstance(entry, CIE): + cie = entry + else: # FDE + cie = entry.cie + pc = entry['initial_location'] + + s = '' + for instr in entry.instructions: + name = instruction_name(instr.opcode) + + if name in ('DW_CFA_offset', + 'DW_CFA_offset_extended', 'DW_CFA_offset_extended_sf', + 'DW_CFA_val_offset', 'DW_CFA_val_offset_sf'): + s += ' %s: %s at cfa%+d\n' % ( + name, _full_reg_name(instr.args[0]), + instr.args[1] * cie['data_alignment_factor']) + elif name in ( 'DW_CFA_restore', 'DW_CFA_restore_extended', + 'DW_CFA_undefined', 'DW_CFA_same_value', + 'DW_CFA_def_cfa_register'): + s += ' %s: %s\n' % (name, _full_reg_name(instr.args[0])) + elif name == 'DW_CFA_register': + s += ' %s: %s in %s' % ( + name, _full_reg_name(instr.args[0]), + _full_reg_name(instr.args[1])) + elif name == 'DW_CFA_set_loc': + pc = instr.args[0] + s += ' %s: %08x\n' % (name, pc) + elif name in ( 'DW_CFA_advance_loc1', 'DW_CFA_advance_loc2', + 'DW_CFA_advance_loc4', 'DW_CFA_advance_loc'): + _assert_FDE_instruction(instr) + factored_offset = instr.args[0] * cie['code_alignment_factor'] + s += ' %s: %s to %016x\n' % ( + name, factored_offset, factored_offset + pc) + pc += factored_offset + elif name in ( 'DW_CFA_remember_state', 'DW_CFA_restore_state', + 'DW_CFA_nop'): + s += ' %s\n' % name + elif name == 'DW_CFA_def_cfa': + s += ' %s: %s ofs %s\n' % ( + name, _full_reg_name(instr.args[0]), instr.args[1]) + elif name == 'DW_CFA_def_cfa_sf': + s += ' %s: %s ofs %s\n' % ( + name, _full_reg_name(instr.args[0]), + instr.args[1] * cie['data_alignment_factor']) + elif name == 'DW_CFA_def_cfa_offset': + s += ' %s: %s\n' % (name, instr.args[0]) + elif name == 'DW_CFA_def_cfa_expression': + expr_dumper = ExprDumper(entry.structs) + expr_dumper.process_expr(instr.args[0]) + s += ' %s: (%s)\n' % (name, expr_dumper.get_str()) + elif name == 'DW_CFA_expression': + expr_dumper = ExprDumper(entry.structs) + expr_dumper.process_expr(instr.args[1]) + s += ' %s: %s (%s)\n' % ( + name, _full_reg_name(instr.args[0]), expr_dumper.get_str()) + else: + s += ' %s: \n' % name + + return s + + +def describe_CFI_register_rule(rule): + s = _DESCR_CFI_REGISTER_RULE_TYPE[rule.type] + if rule.type in ('OFFSET', 'VAL_OFFSET'): + s += '%+d' % rule.arg + elif rule.type == 'REGISTER': + s += describe_reg_name(rule.arg) + return s + + +def describe_CFI_CFA_rule(rule): + if rule.expr: + return 'exp' + else: + return '%s%+d' % (describe_reg_name(rule.reg), rule.offset) + + +def describe_DWARF_expr(expr, structs): + """ Textual description of a DWARF expression encoded in 'expr'. + structs should come from the entity encompassing the expression - it's + needed to be able to parse it correctly. + """ + # Since this function can be called a lot, initializing a fresh new + # ExprDumper per call is expensive. So a rudimentary caching scheme is in + # place to create only one such dumper per instance of structs. + cache_key = id(structs) + if cache_key not in _DWARF_EXPR_DUMPER_CACHE: + _DWARF_EXPR_DUMPER_CACHE[cache_key] = \ + ExprDumper(structs) + dwarf_expr_dumper = _DWARF_EXPR_DUMPER_CACHE[cache_key] + dwarf_expr_dumper.clear() + dwarf_expr_dumper.process_expr(expr) + return '(' + dwarf_expr_dumper.get_str() + ')' + + +def describe_reg_name(regnum, machine_arch=None, default=True): + """ Provide a textual description for a register name, given its serial + number. The number is expected to be valid. + """ + if machine_arch is None: + machine_arch = _MACHINE_ARCH + + if machine_arch == 'x86': + return _REG_NAMES_x86[regnum] + elif machine_arch == 'x64': + return _REG_NAMES_x64[regnum] + elif default: + return 'r%s' % regnum + else: + return None + +#------------------------------------------------------------------------------- + +# The machine architecture. Set globally via set_global_machine_arch +# +_MACHINE_ARCH = None + + +def _describe_attr_ref(attr, die, section_offset): + return '<0x%x>' % (attr.value + die.cu.cu_offset) + +def _describe_attr_value_passthrough(attr, die, section_offset): + return attr.value + +def _describe_attr_hex(attr, die, section_offset): + return '0x%x' % (attr.value) + +def _describe_attr_hex_addr(attr, die, section_offset): + return '<0x%x>' % (attr.value) + +def _describe_attr_split_64bit(attr, die, section_offset): + low_word = attr.value & 0xFFFFFFFF + high_word = (attr.value >> 32) & 0xFFFFFFFF + return '0x%x 0x%x' % (low_word, high_word) + +def _describe_attr_strp(attr, die, section_offset): + return '(indirect string, offset: 0x%x): %s' % ( + attr.raw_value, bytes2str(attr.value)) + +def _describe_attr_string(attr, die, section_offset): + return bytes2str(attr.value) + +def _describe_attr_debool(attr, die, section_offset): + """ To be consistent with readelf, generate 1 for True flags, 0 for False + flags. + """ + return '1' if attr.value else '0' + +def _describe_attr_present(attr, die, section_offset): + """ Some forms may simply mean that an attribute is present, + without providing any value. + """ + return '1' + +def _describe_attr_block(attr, die, section_offset): + s = '%s byte block: ' % len(attr.value) + s += ' '.join('%x' % item for item in attr.value) + ' ' + return s + + +_ATTR_DESCRIPTION_MAP = defaultdict( + lambda: _describe_attr_value_passthrough, # default_factory + + DW_FORM_ref1=_describe_attr_ref, + DW_FORM_ref2=_describe_attr_ref, + DW_FORM_ref4=_describe_attr_ref, + DW_FORM_ref8=_describe_attr_split_64bit, + DW_FORM_ref_udata=_describe_attr_ref, + DW_FORM_ref_addr=_describe_attr_hex_addr, + DW_FORM_data4=_describe_attr_hex, + DW_FORM_data8=_describe_attr_hex, + DW_FORM_addr=_describe_attr_hex, + DW_FORM_sec_offset=_describe_attr_hex, + DW_FORM_flag=_describe_attr_debool, + DW_FORM_data1=_describe_attr_value_passthrough, + DW_FORM_data2=_describe_attr_value_passthrough, + DW_FORM_sdata=_describe_attr_value_passthrough, + DW_FORM_udata=_describe_attr_value_passthrough, + DW_FORM_string=_describe_attr_string, + DW_FORM_strp=_describe_attr_strp, + DW_FORM_block1=_describe_attr_block, + DW_FORM_block2=_describe_attr_block, + DW_FORM_block4=_describe_attr_block, + DW_FORM_block=_describe_attr_block, + DW_FORM_flag_present=_describe_attr_present, + DW_FORM_exprloc=_describe_attr_block, + DW_FORM_ref_sig8=_describe_attr_ref, +) + + +_DESCR_DW_INL = { + DW_INL_not_inlined: '(not inlined)', + DW_INL_inlined: '(inlined)', + DW_INL_declared_not_inlined: '(declared as inline but ignored)', + DW_INL_declared_inlined: '(declared as inline and inlined)', +} + +_DESCR_DW_LANG = { + DW_LANG_C89: '(ANSI C)', + DW_LANG_C: '(non-ANSI C)', + DW_LANG_Ada83: '(Ada)', + DW_LANG_C_plus_plus: '(C++)', + DW_LANG_Cobol74: '(Cobol 74)', + DW_LANG_Cobol85: '(Cobol 85)', + DW_LANG_Fortran77: '(FORTRAN 77)', + DW_LANG_Fortran90: '(Fortran 90)', + DW_LANG_Pascal83: '(ANSI Pascal)', + DW_LANG_Modula2: '(Modula 2)', + DW_LANG_Java: '(Java)', + DW_LANG_C99: '(ANSI C99)', + DW_LANG_Ada95: '(ADA 95)', + DW_LANG_Fortran95: '(Fortran 95)', + DW_LANG_PLI: '(PLI)', + DW_LANG_ObjC: '(Objective C)', + DW_LANG_ObjC_plus_plus: '(Objective C++)', + DW_LANG_UPC: '(Unified Parallel C)', + DW_LANG_D: '(D)', + DW_LANG_Python: '(Python)', + DW_LANG_Mips_Assembler: '(MIPS assembler)', + DW_LANG_Upc: '(nified Parallel C)', + DW_LANG_HP_Bliss: '(HP Bliss)', + DW_LANG_HP_Basic91: '(HP Basic 91)', + DW_LANG_HP_Pascal91: '(HP Pascal 91)', + DW_LANG_HP_IMacro: '(HP IMacro)', + DW_LANG_HP_Assembler: '(HP assembler)', +} + +_DESCR_DW_ATE = { + DW_ATE_void: '(void)', + DW_ATE_address: '(machine address)', + DW_ATE_boolean: '(boolean)', + DW_ATE_complex_float: '(complex float)', + DW_ATE_float: '(float)', + DW_ATE_signed: '(signed)', + DW_ATE_signed_char: '(signed char)', + DW_ATE_unsigned: '(unsigned)', + DW_ATE_unsigned_char: '(unsigned char)', + DW_ATE_imaginary_float: '(imaginary float)', + DW_ATE_decimal_float: '(decimal float)', + DW_ATE_packed_decimal: '(packed_decimal)', + DW_ATE_numeric_string: '(numeric_string)', + DW_ATE_edited: '(edited)', + DW_ATE_signed_fixed: '(signed_fixed)', + DW_ATE_unsigned_fixed: '(unsigned_fixed)', + DW_ATE_HP_float80: '(HP_float80)', + DW_ATE_HP_complex_float80: '(HP_complex_float80)', + DW_ATE_HP_float128: '(HP_float128)', + DW_ATE_HP_complex_float128: '(HP_complex_float128)', + DW_ATE_HP_floathpintel: '(HP_floathpintel)', + DW_ATE_HP_imaginary_float80: '(HP_imaginary_float80)', + DW_ATE_HP_imaginary_float128: '(HP_imaginary_float128)', +} + +_DESCR_DW_ACCESS = { + DW_ACCESS_public: '(public)', + DW_ACCESS_protected: '(protected)', + DW_ACCESS_private: '(private)', +} + +_DESCR_DW_VIS = { + DW_VIS_local: '(local)', + DW_VIS_exported: '(exported)', + DW_VIS_qualified: '(qualified)', +} + +_DESCR_DW_VIRTUALITY = { + DW_VIRTUALITY_none: '(none)', + DW_VIRTUALITY_virtual: '(virtual)', + DW_VIRTUALITY_pure_virtual: '(pure virtual)', +} + +_DESCR_DW_ID_CASE = { + DW_ID_case_sensitive: '(case_sensitive)', + DW_ID_up_case: '(up_case)', + DW_ID_down_case: '(down_case)', + DW_ID_case_insensitive: '(case_insensitive)', +} + +_DESCR_DW_CC = { + DW_CC_normal: '(normal)', + DW_CC_program: '(program)', + DW_CC_nocall: '(nocall)', +} + +_DESCR_DW_ORD = { + DW_ORD_row_major: '(row major)', + DW_ORD_col_major: '(column major)', +} + +_DESCR_CFI_REGISTER_RULE_TYPE = dict( + UNDEFINED='u', + SAME_VALUE='s', + OFFSET='c', + VAL_OFFSET='v', + REGISTER='', + EXPRESSION='exp', + VAL_EXPRESSION='vexp', + ARCHITECTURAL='a', +) + +def _make_extra_mapper(mapping, default, default_interpolate_value=False): + """ Create a mapping function from attribute parameters to an extra + value that should be displayed. + """ + def mapper(attr, die, section_offset): + if default_interpolate_value: + d = default % attr.value + else: + d = default + return mapping.get(attr.value, d) + return mapper + + +def _make_extra_string(s=''): + """ Create an extra function that just returns a constant string. + """ + def extra(attr, die, section_offset): + return s + return extra + + +_DWARF_EXPR_DUMPER_CACHE = {} + +def _location_list_extra(attr, die, section_offset): + # According to section 2.6 of the DWARF spec v3, class loclistptr means + # a location list, and class block means a location expression. + # + if attr.form in ('DW_FORM_data4', 'DW_FORM_data8'): + return '(location list)' + else: + return describe_DWARF_expr(attr.value, die.cu.structs) + + +def _import_extra(attr, die, section_offset): + # For DW_AT_import the value points to a DIE (that can be either in the + # current DIE's CU or in another CU, depending on the FORM). The extra + # information for it is the abbreviation number in this DIE and its tag. + if attr.form == 'DW_FORM_ref_addr': + # Absolute offset value + ref_die_offset = section_offset + attr.value + else: + # Relative offset to the current DIE's CU + ref_die_offset = attr.value + die.cu.cu_offset + + # Now find the CU this DIE belongs to (since we have to find its abbrev + # table). This is done by linearly scanning through all CUs, looking for + # one spanning an address space containing the referred DIE's offset. + for cu in die.dwarfinfo.iter_CUs(): + if cu['unit_length'] + cu.cu_offset > ref_die_offset >= cu.cu_offset: + # Once we have the CU, we can actually parse this DIE from the + # stream. + with preserve_stream_pos(die.stream): + ref_die = DIE(cu, die.stream, ref_die_offset) + #print '&&& ref_die', ref_die + return '[Abbrev Number: %s (%s)]' % ( + ref_die.abbrev_code, ref_die.tag) + + return '[unknown]' + + +_EXTRA_INFO_DESCRIPTION_MAP = defaultdict( + lambda: _make_extra_string(''), # default_factory + + DW_AT_inline=_make_extra_mapper( + _DESCR_DW_INL, '(Unknown inline attribute value: %x', + default_interpolate_value=True), + DW_AT_language=_make_extra_mapper( + _DESCR_DW_LANG, '(Unknown: %x)', default_interpolate_value=True), + DW_AT_encoding=_make_extra_mapper(_DESCR_DW_ATE, '(unknown type)'), + DW_AT_accessibility=_make_extra_mapper( + _DESCR_DW_ACCESS, '(unknown accessibility)'), + DW_AT_visibility=_make_extra_mapper( + _DESCR_DW_VIS, '(unknown visibility)'), + DW_AT_virtuality=_make_extra_mapper( + _DESCR_DW_VIRTUALITY, '(unknown virtuality)'), + DW_AT_identifier_case=_make_extra_mapper( + _DESCR_DW_ID_CASE, '(unknown case)'), + DW_AT_calling_convention=_make_extra_mapper( + _DESCR_DW_CC, '(unknown convention)'), + DW_AT_ordering=_make_extra_mapper( + _DESCR_DW_ORD, '(undefined)'), + DW_AT_frame_base=_location_list_extra, + DW_AT_location=_location_list_extra, + DW_AT_string_length=_location_list_extra, + DW_AT_return_addr=_location_list_extra, + DW_AT_data_member_location=_location_list_extra, + DW_AT_vtable_elem_location=_location_list_extra, + DW_AT_segment=_location_list_extra, + DW_AT_static_link=_location_list_extra, + DW_AT_use_location=_location_list_extra, + DW_AT_allocated=_location_list_extra, + DW_AT_associated=_location_list_extra, + DW_AT_data_location=_location_list_extra, + DW_AT_stride=_location_list_extra, + DW_AT_import=_import_extra, +) + +# 8 in a line, for easier counting +_REG_NAMES_x86 = [ + 'eax', 'ecx', 'edx', 'ebx', 'esp', 'ebp', 'esi', 'edi', + 'eip', 'eflags', '', 'st0', 'st1', 'st2', 'st3', 'st4', + 'st5', 'st6', 'st7', '', '', 'xmm0', 'xmm1', 'xmm2', + 'xmm3', 'xmm4', 'xmm5', 'xmm6', 'xmm7', 'mm0', 'mm1', 'mm2', + 'mm3', 'mm4', 'mm5', 'mm6', 'mm7', 'fcw', 'fsw', 'mxcsr', + 'es', 'cs', 'ss', 'ds', 'fs', 'gs', '', '', 'tr', 'ldtr' +] + +_REG_NAMES_x64 = [ + 'rax', 'rdx', 'rcx', 'rbx', 'rsi', 'rdi', 'rbp', 'rsp', + 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15', + 'rip', 'xmm0', 'xmm1', 'xmm2', 'xmm3', 'xmm4', 'xmm5', 'xmm6', + 'xmm7', 'xmm8', 'xmm9', 'xmm10', 'xmm11', 'xmm12', 'xmm13', 'xmm14', + 'xmm15', 'st0', 'st1', 'st2', 'st3', 'st4', 'st5', 'st6', + 'st7', 'mm0', 'mm1', 'mm2', 'mm3', 'mm4', 'mm5', 'mm6', + 'mm7', 'rflags', 'es', 'cs', 'ss', 'ds', 'fs', 'gs', + '', '', 'fs.base', 'gs.base', '', '', 'tr', 'ldtr', + 'mxcsr', 'fcw', 'fsw' +] + + +class ExprDumper(GenericExprVisitor): + """ A concrete visitor for DWARF expressions that dumps a textual + representation of the complete expression. + + Usage: after creation, call process_expr, and then get_str for a + semicolon-delimited string representation of the decoded expression. + """ + def __init__(self, structs): + super(ExprDumper, self).__init__(structs) + self._init_lookups() + self._str_parts = [] + + def clear(self): + self._str_parts = [] + + def get_str(self): + return '; '.join(self._str_parts) + + def _init_lookups(self): + self._ops_with_decimal_arg = set([ + 'DW_OP_const1u', 'DW_OP_const1s', 'DW_OP_const2u', 'DW_OP_const2s', + 'DW_OP_const4u', 'DW_OP_const4s', 'DW_OP_constu', 'DW_OP_consts', + 'DW_OP_pick', 'DW_OP_plus_uconst', 'DW_OP_bra', 'DW_OP_skip', + 'DW_OP_fbreg', 'DW_OP_piece', 'DW_OP_deref_size', + 'DW_OP_xderef_size', 'DW_OP_regx',]) + + for n in range(0, 32): + self._ops_with_decimal_arg.add('DW_OP_breg%s' % n) + + self._ops_with_two_decimal_args = set([ + 'DW_OP_const8u', 'DW_OP_const8s', 'DW_OP_bregx', 'DW_OP_bit_piece']) + + self._ops_with_hex_arg = set( + ['DW_OP_addr', 'DW_OP_call2', 'DW_OP_call4', 'DW_OP_call_ref']) + + def _after_visit(self, opcode, opcode_name, args): + self._str_parts.append(self._dump_to_string(opcode, opcode_name, args)) + + def _dump_to_string(self, opcode, opcode_name, args): + if len(args) == 0: + if opcode_name.startswith('DW_OP_reg'): + regnum = int(opcode_name[9:]) + return '%s (%s)' % ( + opcode_name, + describe_reg_name(regnum, _MACHINE_ARCH)) + else: + return opcode_name + elif opcode_name in self._ops_with_decimal_arg: + if opcode_name.startswith('DW_OP_breg'): + regnum = int(opcode_name[10:]) + return '%s (%s): %s' % ( + opcode_name, + describe_reg_name(regnum, _MACHINE_ARCH), + args[0]) + elif opcode_name.endswith('regx'): + # applies to both regx and bregx + return '%s: %s (%s)' % ( + opcode_name, + args[0], + describe_reg_name(args[0], _MACHINE_ARCH)) + else: + return '%s: %s' % (opcode_name, args[0]) + elif opcode_name in self._ops_with_hex_arg: + return '%s: %x' % (opcode_name, args[0]) + elif opcode_name in self._ops_with_two_decimal_args: + return '%s: %s %s' % (opcode_name, args[0], args[1]) + else: + return '' % opcode_name + + + diff --git a/tools/utils/contrib/elftools/dwarf/die.py b/tools/utils/contrib/elftools/dwarf/die.py new file mode 100755 index 0000000000..1b42066c20 --- /dev/null +++ b/tools/utils/contrib/elftools/dwarf/die.py @@ -0,0 +1,220 @@ +#------------------------------------------------------------------------------- +# elftools: dwarf/die.py +# +# DWARF Debugging Information Entry +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +from collections import namedtuple, OrderedDict +import os + +from ..common.exceptions import DWARFError +from ..common.py3compat import bytes2str, iteritems +from ..common.utils import struct_parse, preserve_stream_pos +from .enums import DW_FORM_raw2name + + +# AttributeValue - describes an attribute value in the DIE: +# +# name: +# The name (DW_AT_*) of this attribute +# +# form: +# The DW_FORM_* name of this attribute +# +# value: +# The value parsed from the section and translated accordingly to the form +# (e.g. for a DW_FORM_strp it's the actual string taken from the string table) +# +# raw_value: +# Raw value as parsed from the section - used for debugging and presentation +# (e.g. for a DW_FORM_strp it's the raw string offset into the table) +# +# offset: +# Offset of this attribute's value in the stream (absolute offset, relative +# the beginning of the whole stream) +# +AttributeValue = namedtuple( + 'AttributeValue', 'name form value raw_value offset') + + +class DIE(object): + """ A DWARF debugging information entry. On creation, parses itself from + the stream. Each DIE is held by a CU. + + Accessible attributes: + + tag: + The DIE tag + + size: + The size this DIE occupies in the section + + offset: + The offset of this DIE in the stream + + attributes: + An ordered dictionary mapping attribute names to values. It's + ordered to preserve the order of attributes in the section + + has_children: + Specifies whether this DIE has children + + abbrev_code: + The abbreviation code pointing to an abbreviation entry (note + that this is for informational pusposes only - this object + interacts with its abbreviation table transparently). + + See also the public methods. + """ + def __init__(self, cu, stream, offset): + """ cu: + CompileUnit object this DIE belongs to. Used to obtain context + information (structs, abbrev table, etc.) + + stream, offset: + The stream and offset into it where this DIE's data is located + """ + self.cu = cu + self.dwarfinfo = self.cu.dwarfinfo # get DWARFInfo context + self.stream = stream + self.offset = offset + + self.attributes = OrderedDict() + self.tag = None + self.has_children = None + self.abbrev_code = None + self.size = 0 + self._children = [] + self._parent = None + + self._parse_DIE() + + def is_null(self): + """ Is this a null entry? + """ + return self.tag is None + + def get_parent(self): + """ The parent DIE of this DIE. None if the DIE has no parent (i.e. a + top-level DIE). + """ + return self._parent + + def get_full_path(self): + """ Return the full path filename for the DIE. + + The filename is the join of 'DW_AT_comp_dir' and 'DW_AT_name', + either of which may be missing in practice. Note that its value is + usually a string taken from the .debug_string section and the + returned value will be a string. + """ + comp_dir_attr = self.attributes.get('DW_AT_comp_dir', None) + comp_dir = bytes2str(comp_dir_attr.value) if comp_dir_attr else '' + fname_attr = self.attributes.get('DW_AT_name', None) + fname = bytes2str(fname_attr.value) if fname_attr else '' + return os.path.join(comp_dir, fname) + + def iter_children(self): + """ Yield all children of this DIE + """ + return iter(self._children) + + def iter_siblings(self): + """ Yield all siblings of this DIE + """ + if self._parent: + for sibling in self._parent.iter_children(): + if sibling is not self: + yield sibling + else: + raise StopIteration() + + # The following methods are used while creating the DIE and should not be + # interesting to consumers + # + def add_child(self, die): + self._children.append(die) + + def set_parent(self, die): + self._parent = die + + #------ PRIVATE ------# + + def __repr__(self): + s = 'DIE %s, size=%s, has_chidren=%s\n' % ( + self.tag, self.size, self.has_children) + for attrname, attrval in iteritems(self.attributes): + s += ' |%-18s: %s\n' % (attrname, attrval) + return s + + def __str__(self): + return self.__repr__() + + def _parse_DIE(self): + """ Parses the DIE info from the section, based on the abbreviation + table of the CU + """ + structs = self.cu.structs + + # A DIE begins with the abbreviation code. Read it and use it to + # obtain the abbrev declaration for this DIE. + # Note: here and elsewhere, preserve_stream_pos is used on operations + # that manipulate the stream by reading data from it. + # + self.abbrev_code = struct_parse( + structs.Dwarf_uleb128(''), self.stream, self.offset) + + # This may be a null entry + if self.abbrev_code == 0: + self.size = self.stream.tell() - self.offset + return + + with preserve_stream_pos(self.stream): + abbrev_decl = self.cu.get_abbrev_table().get_abbrev( + self.abbrev_code) + self.tag = abbrev_decl['tag'] + self.has_children = abbrev_decl.has_children() + + # Guided by the attributes listed in the abbreviation declaration, parse + # values from the stream. + # + for name, form in abbrev_decl.iter_attr_specs(): + attr_offset = self.stream.tell() + raw_value = struct_parse(structs.Dwarf_dw_form[form], self.stream) + + value = self._translate_attr_value(form, raw_value) + self.attributes[name] = AttributeValue( + name=name, + form=form, + value=value, + raw_value=raw_value, + offset=attr_offset) + + self.size = self.stream.tell() - self.offset + + def _translate_attr_value(self, form, raw_value): + """ Translate a raw attr value according to the form + """ + value = None + if form == 'DW_FORM_strp': + with preserve_stream_pos(self.stream): + value = self.dwarfinfo.get_string_from_table(raw_value) + elif form == 'DW_FORM_flag': + value = not raw_value == 0 + elif form == 'DW_FORM_indirect': + try: + form = DW_FORM_raw2name[raw_value] + except KeyError as err: + raise DWARFError( + 'Found DW_FORM_indirect with unknown raw_value=' + + str(raw_value)) + + raw_value = struct_parse( + self.cu.structs.Dwarf_dw_form[form], self.stream) + # Let's hope this doesn't get too deep :-) + return self._translate_attr_value(form, raw_value) + else: + value = raw_value + return value diff --git a/tools/utils/contrib/elftools/dwarf/dwarf_expr.py b/tools/utils/contrib/elftools/dwarf/dwarf_expr.py new file mode 100755 index 0000000000..270a78165b --- /dev/null +++ b/tools/utils/contrib/elftools/dwarf/dwarf_expr.py @@ -0,0 +1,257 @@ +#------------------------------------------------------------------------------- +# elftools: dwarf/dwarf_expr.py +# +# Decoding DWARF expressions +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +from ..common.py3compat import BytesIO, iteritems +from ..common.utils import struct_parse, bytelist2string + + +# DWARF expression opcodes. name -> opcode mapping +DW_OP_name2opcode = dict( + DW_OP_addr=0x03, + DW_OP_deref=0x06, + DW_OP_const1u=0x08, + DW_OP_const1s=0x09, + DW_OP_const2u=0x0a, + DW_OP_const2s=0x0b, + DW_OP_const4u=0x0c, + DW_OP_const4s=0x0d, + DW_OP_const8u=0x0e, + DW_OP_const8s=0x0f, + DW_OP_constu=0x10, + DW_OP_consts=0x11, + DW_OP_dup=0x12, + DW_OP_drop=0x13, + DW_OP_over=0x14, + DW_OP_pick=0x15, + DW_OP_swap=0x16, + DW_OP_rot=0x17, + DW_OP_xderef=0x18, + DW_OP_abs=0x19, + DW_OP_and=0x1a, + DW_OP_div=0x1b, + DW_OP_minus=0x1c, + DW_OP_mod=0x1d, + DW_OP_mul=0x1e, + DW_OP_neg=0x1f, + DW_OP_not=0x20, + DW_OP_or=0x21, + DW_OP_plus=0x22, + DW_OP_plus_uconst=0x23, + DW_OP_shl=0x24, + DW_OP_shr=0x25, + DW_OP_shra=0x26, + DW_OP_xor=0x27, + DW_OP_bra=0x28, + DW_OP_eq=0x29, + DW_OP_ge=0x2a, + DW_OP_gt=0x2b, + DW_OP_le=0x2c, + DW_OP_lt=0x2d, + DW_OP_ne=0x2e, + DW_OP_skip=0x2f, + DW_OP_regx=0x90, + DW_OP_fbreg=0x91, + DW_OP_bregx=0x92, + DW_OP_piece=0x93, + DW_OP_deref_size=0x94, + DW_OP_xderef_size=0x95, + DW_OP_nop=0x96, + DW_OP_push_object_address=0x97, + DW_OP_call2=0x98, + DW_OP_call4=0x99, + DW_OP_call_ref=0x9a, + DW_OP_form_tls_address=0x9b, + DW_OP_call_frame_cfa=0x9c, + DW_OP_bit_piece=0x9d, +) + +def _generate_dynamic_values(map, prefix, index_start, index_end, value_start): + """ Generate values in a map (dict) dynamically. Each key starts with + a (string) prefix, followed by an index in the inclusive range + [index_start, index_end]. The values start at value_start. + """ + for index in range(index_start, index_end + 1): + name = '%s%s' % (prefix, index) + value = value_start + index - index_start + map[name] = value + +_generate_dynamic_values(DW_OP_name2opcode, 'DW_OP_lit', 0, 31, 0x30) +_generate_dynamic_values(DW_OP_name2opcode, 'DW_OP_reg', 0, 31, 0x50) +_generate_dynamic_values(DW_OP_name2opcode, 'DW_OP_breg', 0, 31, 0x70) + +# opcode -> name mapping +DW_OP_opcode2name = dict((v, k) for k, v in iteritems(DW_OP_name2opcode)) + + +class GenericExprVisitor(object): + """ A DWARF expression is a sequence of instructions encoded in a block + of bytes. This class decodes the sequence into discrete instructions + with their arguments and allows generic "visiting" to process them. + + Usage: subclass this class, and override the needed methods. The + easiest way would be to just override _after_visit, which gets passed + each decoded instruction (with its arguments) in order. Clients of + the visitor then just execute process_expr. The subclass can keep + its own internal information updated in _after_visit and provide + methods to extract it. For a good example of this usage, see the + ExprDumper class in the descriptions module. + + A more complex usage could be to override visiting methods for + specific instructions, by placing them into the dispatch table. + """ + def __init__(self, structs): + self.structs = structs + self._init_dispatch_table() + self.stream = None + self._cur_opcode = None + self._cur_opcode_name = None + self._cur_args = [] + + def process_expr(self, expr): + """ Process (visit) a DWARF expression. expr should be a list of + (integer) byte values. + """ + self.stream = BytesIO(bytelist2string(expr)) + + while True: + # Get the next opcode from the stream. If nothing is left in the + # stream, we're done. + byte = self.stream.read(1) + if len(byte) == 0: + break + + # Decode the opcode and its name + self._cur_opcode = ord(byte) + self._cur_opcode_name = DW_OP_opcode2name.get( + self._cur_opcode, 'OP:0x%x' % self._cur_opcode) + # Will be filled in by visitors + self._cur_args = [] + + # Dispatch to a visitor function + visitor = self._dispatch_table.get( + self._cur_opcode, + self._default_visitor) + visitor(self._cur_opcode, self._cur_opcode_name) + + # Finally call the post-visit function + self._after_visit( + self._cur_opcode, self._cur_opcode_name, self._cur_args) + + def _after_visit(self, opcode, opcode_name, args): + pass + + def _default_visitor(self, opcode, opcode_name): + pass + + def _visit_OP_with_no_args(self, opcode, opcode_name): + self._cur_args = [] + + def _visit_OP_addr(self, opcode, opcode_name): + self._cur_args = [ + struct_parse(self.structs.Dwarf_target_addr(''), self.stream)] + + def _make_visitor_arg_struct(self, struct_arg): + """ Create a visitor method for an opcode that that accepts a single + argument, specified by a struct. + """ + def visitor(opcode, opcode_name): + self._cur_args = [struct_parse(struct_arg, self.stream)] + return visitor + + def _make_visitor_arg_struct2(self, struct_arg1, struct_arg2): + """ Create a visitor method for an opcode that that accepts two + arguments, specified by structs. + """ + def visitor(opcode, opcode_name): + self._cur_args = [ + struct_parse(struct_arg1, self.stream), + struct_parse(struct_arg2, self.stream)] + return visitor + + def _init_dispatch_table(self): + self._dispatch_table = {} + def add(opcode_name, func): + self._dispatch_table[DW_OP_name2opcode[opcode_name]] = func + + add('DW_OP_addr', self._visit_OP_addr) + add('DW_OP_const1u', + self._make_visitor_arg_struct(self.structs.Dwarf_uint8(''))) + add('DW_OP_const1s', + self._make_visitor_arg_struct(self.structs.Dwarf_int8(''))) + add('DW_OP_const2u', + self._make_visitor_arg_struct(self.structs.Dwarf_uint16(''))) + add('DW_OP_const2s', + self._make_visitor_arg_struct(self.structs.Dwarf_int16(''))) + add('DW_OP_const4u', + self._make_visitor_arg_struct(self.structs.Dwarf_uint32(''))) + add('DW_OP_const4s', + self._make_visitor_arg_struct(self.structs.Dwarf_int32(''))) + add('DW_OP_const8u', + self._make_visitor_arg_struct2( + self.structs.Dwarf_uint32(''), + self.structs.Dwarf_uint32(''))) + add('DW_OP_const8s', + self._make_visitor_arg_struct2( + self.structs.Dwarf_int32(''), + self.structs.Dwarf_int32(''))) + add('DW_OP_constu', + self._make_visitor_arg_struct(self.structs.Dwarf_uleb128(''))) + add('DW_OP_consts', + self._make_visitor_arg_struct(self.structs.Dwarf_sleb128(''))) + add('DW_OP_pick', + self._make_visitor_arg_struct(self.structs.Dwarf_uint8(''))) + add('DW_OP_plus_uconst', + self._make_visitor_arg_struct(self.structs.Dwarf_uleb128(''))) + add('DW_OP_bra', + self._make_visitor_arg_struct(self.structs.Dwarf_int16(''))) + add('DW_OP_skip', + self._make_visitor_arg_struct(self.structs.Dwarf_int16(''))) + + for opname in [ 'DW_OP_deref', 'DW_OP_dup', 'DW_OP_drop', 'DW_OP_over', + 'DW_OP_swap', 'DW_OP_swap', 'DW_OP_rot', 'DW_OP_xderef', + 'DW_OP_abs', 'DW_OP_and', 'DW_OP_div', 'DW_OP_minus', + 'DW_OP_mod', 'DW_OP_mul', 'DW_OP_neg', 'DW_OP_not', + 'DW_OP_plus', 'DW_OP_shl', 'DW_OP_shr', 'DW_OP_shra', + 'DW_OP_xor', 'DW_OP_eq', 'DW_OP_ge', 'DW_OP_gt', + 'DW_OP_le', 'DW_OP_lt', 'DW_OP_ne', 'DW_OP_nop', + 'DW_OP_push_object_address', 'DW_OP_form_tls_address', + 'DW_OP_call_frame_cfa']: + add(opname, self._visit_OP_with_no_args) + + for n in range(0, 32): + add('DW_OP_lit%s' % n, self._visit_OP_with_no_args) + add('DW_OP_reg%s' % n, self._visit_OP_with_no_args) + add('DW_OP_breg%s' % n, + self._make_visitor_arg_struct(self.structs.Dwarf_sleb128(''))) + + add('DW_OP_fbreg', + self._make_visitor_arg_struct(self.structs.Dwarf_sleb128(''))) + add('DW_OP_regx', + self._make_visitor_arg_struct(self.structs.Dwarf_uleb128(''))) + add('DW_OP_bregx', + self._make_visitor_arg_struct2( + self.structs.Dwarf_uleb128(''), + self.structs.Dwarf_sleb128(''))) + add('DW_OP_piece', + self._make_visitor_arg_struct(self.structs.Dwarf_uleb128(''))) + add('DW_OP_bit_piece', + self._make_visitor_arg_struct2( + self.structs.Dwarf_uleb128(''), + self.structs.Dwarf_uleb128(''))) + add('DW_OP_deref_size', + self._make_visitor_arg_struct(self.structs.Dwarf_int8(''))) + add('DW_OP_xderef_size', + self._make_visitor_arg_struct(self.structs.Dwarf_int8(''))) + add('DW_OP_call2', + self._make_visitor_arg_struct(self.structs.Dwarf_uint16(''))) + add('DW_OP_call4', + self._make_visitor_arg_struct(self.structs.Dwarf_uint32(''))) + add('DW_OP_call_ref', + self._make_visitor_arg_struct(self.structs.Dwarf_offset(''))) + + diff --git a/tools/utils/contrib/elftools/dwarf/dwarfinfo.py b/tools/utils/contrib/elftools/dwarf/dwarfinfo.py new file mode 100755 index 0000000000..1995fc88f7 --- /dev/null +++ b/tools/utils/contrib/elftools/dwarf/dwarfinfo.py @@ -0,0 +1,275 @@ +#------------------------------------------------------------------------------- +# elftools: dwarf/dwarfinfo.py +# +# DWARFInfo - Main class for accessing DWARF debug information +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +from collections import namedtuple + +from ..common.exceptions import DWARFError +from ..common.utils import (struct_parse, dwarf_assert, + parse_cstring_from_stream) +from .structs import DWARFStructs +from .compileunit import CompileUnit +from .abbrevtable import AbbrevTable +from .lineprogram import LineProgram +from .callframe import CallFrameInfo +from .locationlists import LocationLists +from .ranges import RangeLists + + +# Describes a debug section +# +# stream: a stream object containing the data of this section +# name: section name in the container file +# global_offset: the global offset of the section in its container file +# size: the size of the section's data, in bytes +# +# 'name' and 'global_offset' are for descriptional purposes only and +# aren't strictly required for the DWARF parsing to work. +# +DebugSectionDescriptor = namedtuple('DebugSectionDescriptor', + 'stream name global_offset size') + + +# Some configuration parameters for the DWARF reader. This exists to allow +# DWARFInfo to be independent from any specific file format/container. +# +# little_endian: +# boolean flag specifying whether the data in the file is little endian +# +# machine_arch: +# Machine architecture as a string. For example 'x86' or 'x64' +# +# default_address_size: +# The default address size for the container file (sizeof pointer, in bytes) +# +DwarfConfig = namedtuple('DwarfConfig', + 'little_endian machine_arch default_address_size') + + +class DWARFInfo(object): + """ Acts also as a "context" to other major objects, bridging between + various parts of the debug infromation. + """ + def __init__(self, + config, + debug_info_sec, + debug_abbrev_sec, + debug_frame_sec, + eh_frame_sec, + debug_str_sec, + debug_loc_sec, + debug_ranges_sec, + debug_line_sec): + """ config: + A DwarfConfig object + + debug_*_sec: + DebugSectionDescriptor for a section. Pass None for sections + that don't exist. These arguments are best given with + keyword syntax. + """ + self.config = config + self.debug_info_sec = debug_info_sec + self.debug_abbrev_sec = debug_abbrev_sec + self.debug_frame_sec = debug_frame_sec + self.eh_frame_sec = eh_frame_sec + self.debug_str_sec = debug_str_sec + self.debug_loc_sec = debug_loc_sec + self.debug_ranges_sec = debug_ranges_sec + self.debug_line_sec = debug_line_sec + + # This is the DWARFStructs the context uses, so it doesn't depend on + # DWARF format and address_size (these are determined per CU) - set them + # to default values. + self.structs = DWARFStructs( + little_endian=self.config.little_endian, + dwarf_format=32, + address_size=self.config.default_address_size) + + # Cache for abbrev tables: a dict keyed by offset + self._abbrevtable_cache = {} + + def iter_CUs(self): + """ Yield all the compile units (CompileUnit objects) in the debug info + """ + return self._parse_CUs_iter() + + def get_abbrev_table(self, offset): + """ Get an AbbrevTable from the given offset in the debug_abbrev + section. + + The only verification done on the offset is that it's within the + bounds of the section (if not, an exception is raised). + It is the caller's responsibility to make sure the offset actually + points to a valid abbreviation table. + + AbbrevTable objects are cached internally (two calls for the same + offset will return the same object). + """ + dwarf_assert( + offset < self.debug_abbrev_sec.size, + "Offset '0x%x' to abbrev table out of section bounds" % offset) + if offset not in self._abbrevtable_cache: + self._abbrevtable_cache[offset] = AbbrevTable( + structs=self.structs, + stream=self.debug_abbrev_sec.stream, + offset=offset) + return self._abbrevtable_cache[offset] + + def get_string_from_table(self, offset): + """ Obtain a string from the string table section, given an offset + relative to the section. + """ + return parse_cstring_from_stream(self.debug_str_sec.stream, offset) + + def line_program_for_CU(self, CU): + """ Given a CU object, fetch the line program it points to from the + .debug_line section. + If the CU doesn't point to a line program, return None. + """ + # The line program is pointed to by the DW_AT_stmt_list attribute of + # the top DIE of a CU. + top_DIE = CU.get_top_DIE() + if 'DW_AT_stmt_list' in top_DIE.attributes: + return self._parse_line_program_at_offset( + top_DIE.attributes['DW_AT_stmt_list'].value, CU.structs) + else: + return None + + def has_CFI(self): + """ Does this dwarf info have a dwarf_frame CFI section? + """ + return self.debug_frame_sec is not None + + def CFI_entries(self): + """ Get a list of dwarf_frame CFI entries from the .debug_frame section. + """ + cfi = CallFrameInfo( + stream=self.debug_frame_sec.stream, + size=self.debug_frame_sec.size, + base_structs=self.structs) + return cfi.get_entries() + + def has_EH_CFI(self): + """ Does this dwarf info have a eh_frame CFI section? + """ + return self.eh_frame_sec is not None + + def EH_CFI_entries(self): + """ Get a list of eh_frame CFI entries from the .eh_frame section. + """ + cfi = CallFrameInfo( + stream=self.eh_frame_sec.stream, + size=self.eh_frame_sec.size, + base_structs=self.structs) + return cfi.get_entries() + + def location_lists(self): + """ Get a LocationLists object representing the .debug_loc section of + the DWARF data, or None if this section doesn't exist. + """ + if self.debug_loc_sec: + return LocationLists(self.debug_loc_sec.stream, self.structs) + else: + return None + + def range_lists(self): + """ Get a RangeLists object representing the .debug_ranges section of + the DWARF data, or None if this section doesn't exist. + """ + if self.debug_ranges_sec: + return RangeLists(self.debug_ranges_sec.stream, self.structs) + else: + return None + + #------ PRIVATE ------# + + def _parse_CUs_iter(self): + """ Parse CU entries from debug_info. Yield CUs in order of appearance. + """ + offset = 0 + while offset < self.debug_info_sec.size: + cu = self._parse_CU_at_offset(offset) + # Compute the offset of the next CU in the section. The unit_length + # field of the CU header contains its size not including the length + # field itself. + offset = ( offset + + cu['unit_length'] + + cu.structs.initial_length_field_size()) + yield cu + + def _parse_CU_at_offset(self, offset): + """ Parse and return a CU at the given offset in the debug_info stream. + """ + # Section 7.4 (32-bit and 64-bit DWARF Formats) of the DWARF spec v3 + # states that the first 32-bit word of the CU header determines + # whether the CU is represented with 32-bit or 64-bit DWARF format. + # + # So we peek at the first word in the CU header to determine its + # dwarf format. Based on it, we then create a new DWARFStructs + # instance suitable for this CU and use it to parse the rest. + # + initial_length = struct_parse( + self.structs.Dwarf_uint32(''), self.debug_info_sec.stream, offset) + dwarf_format = 64 if initial_length == 0xFFFFFFFF else 32 + + # At this point we still haven't read the whole header, so we don't + # know the address_size. Therefore, we're going to create structs + # with a default address_size=4. If, after parsing the header, we + # find out address_size is actually 8, we just create a new structs + # object for this CU. + # + cu_structs = DWARFStructs( + little_endian=self.config.little_endian, + dwarf_format=dwarf_format, + address_size=4) + + cu_header = struct_parse( + cu_structs.Dwarf_CU_header, self.debug_info_sec.stream, offset) + if cu_header['address_size'] == 8: + cu_structs = DWARFStructs( + little_endian=self.config.little_endian, + dwarf_format=dwarf_format, + address_size=8) + + cu_die_offset = self.debug_info_sec.stream.tell() + dwarf_assert( + self._is_supported_version(cu_header['version']), + "Expected supported DWARF version. Got '%s'" % cu_header['version']) + return CompileUnit( + header=cu_header, + dwarfinfo=self, + structs=cu_structs, + cu_offset=offset, + cu_die_offset=cu_die_offset) + + def _is_supported_version(self, version): + """ DWARF version supported by this parser + """ + return 2 <= version <= 4 + + def _parse_line_program_at_offset(self, debug_line_offset, structs): + """ Given an offset to the .debug_line section, parse the line program + starting at this offset in the section and return it. + structs is the DWARFStructs object used to do this parsing. + """ + lineprog_header = struct_parse( + structs.Dwarf_lineprog_header, + self.debug_line_sec.stream, + debug_line_offset) + + # Calculate the offset to the next line program (see DWARF 6.2.4) + end_offset = ( debug_line_offset + lineprog_header['unit_length'] + + structs.initial_length_field_size()) + + return LineProgram( + header=lineprog_header, + stream=self.debug_line_sec.stream, + structs=structs, + program_start_offset=self.debug_line_sec.stream.tell(), + program_end_offset=end_offset) + diff --git a/tools/utils/contrib/elftools/dwarf/enums.py b/tools/utils/contrib/elftools/dwarf/enums.py new file mode 100755 index 0000000000..d576dffb50 --- /dev/null +++ b/tools/utils/contrib/elftools/dwarf/enums.py @@ -0,0 +1,283 @@ +#------------------------------------------------------------------------------- +# elftools: dwarf/enums.py +# +# Mappings of enum names to values +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +from ..construct import Pass +from ..common.py3compat import iteritems + + +ENUM_DW_TAG = dict( + DW_TAG_null = 0x00, + DW_TAG_array_type = 0x01, + DW_TAG_class_type = 0x02, + DW_TAG_entry_point = 0x03, + DW_TAG_enumeration_type = 0x04, + DW_TAG_formal_parameter = 0x05, + DW_TAG_imported_declaration = 0x08, + DW_TAG_label = 0x0a, + DW_TAG_lexical_block = 0x0b, + DW_TAG_member = 0x0d, + DW_TAG_pointer_type = 0x0f, + DW_TAG_reference_type = 0x10, + DW_TAG_compile_unit = 0x11, + DW_TAG_string_type = 0x12, + DW_TAG_structure_type = 0x13, + DW_TAG_subroutine_type = 0x15, + DW_TAG_typedef = 0x16, + DW_TAG_union_type = 0x17, + DW_TAG_unspecified_parameters = 0x18, + DW_TAG_variant = 0x19, + DW_TAG_common_block = 0x1a, + DW_TAG_common_inclusion = 0x1b, + DW_TAG_inheritance = 0x1c, + DW_TAG_inlined_subroutine = 0x1d, + DW_TAG_module = 0x1e, + DW_TAG_ptr_to_member_type = 0x1f, + DW_TAG_set_type = 0x20, + DW_TAG_subrange_type = 0x21, + DW_TAG_with_stmt = 0x22, + DW_TAG_access_declaration = 0x23, + DW_TAG_base_type = 0x24, + DW_TAG_catch_block = 0x25, + DW_TAG_const_type = 0x26, + DW_TAG_constant = 0x27, + DW_TAG_enumerator = 0x28, + DW_TAG_file_type = 0x29, + DW_TAG_friend = 0x2a, + DW_TAG_namelist = 0x2b, + DW_TAG_namelist_item = 0x2c, + DW_TAG_namelist_items = 0x2c, + DW_TAG_packed_type = 0x2d, + DW_TAG_subprogram = 0x2e, + + # The DWARF standard defines these as _parameter, not _param, but we + # maintain compatibility with readelf. + DW_TAG_template_type_param = 0x2f, + DW_TAG_template_value_param = 0x30, + + DW_TAG_thrown_type = 0x31, + DW_TAG_try_block = 0x32, + DW_TAG_variant_part = 0x33, + DW_TAG_variable = 0x34, + DW_TAG_volatile_type = 0x35, + DW_TAG_dwarf_procedure = 0x36, + DW_TAG_restrict_type = 0x37, + DW_TAG_interface_type = 0x38, + DW_TAG_namespace = 0x39, + DW_TAG_imported_module = 0x3a, + DW_TAG_unspecified_type = 0x3b, + DW_TAG_partial_unit = 0x3c, + DW_TAG_imported_unit = 0x3d, + DW_TAG_mutable_type = 0x3e, + DW_TAG_condition = 0x3f, + DW_TAG_shared_type = 0x40, + DW_TAG_type_unit = 0x41, + DW_TAG_rvalue_reference_type = 0x42, + + DW_TAG_lo_user = 0x4080, + DW_TAG_hi_user = 0xffff, + + _default_ = Pass, +) + + +ENUM_DW_CHILDREN = dict( + DW_CHILDREN_no = 0x00, + DW_CHILDREN_yes = 0x01, +) + + +ENUM_DW_AT = dict( + DW_AT_null = 0x00, + DW_AT_sibling = 0x01, + DW_AT_location = 0x02, + DW_AT_name = 0x03, + DW_AT_ordering = 0x09, + DW_AT_subscr_data = 0x0a, + DW_AT_byte_size = 0x0b, + DW_AT_bit_offset = 0x0c, + DW_AT_bit_size = 0x0d, + DW_AT_element_list = 0x0f, + DW_AT_stmt_list = 0x10, + DW_AT_low_pc = 0x11, + DW_AT_high_pc = 0x12, + DW_AT_language = 0x13, + DW_AT_member = 0x14, + DW_AT_discr = 0x15, + DW_AT_discr_value = 0x16, + DW_AT_visibility = 0x17, + DW_AT_import = 0x18, + DW_AT_string_length = 0x19, + DW_AT_common_reference = 0x1a, + DW_AT_comp_dir = 0x1b, + DW_AT_const_value = 0x1c, + DW_AT_containing_type = 0x1d, + DW_AT_default_value = 0x1e, + DW_AT_inline = 0x20, + DW_AT_is_optional = 0x21, + DW_AT_lower_bound = 0x22, + DW_AT_producer = 0x25, + DW_AT_prototyped = 0x27, + DW_AT_return_addr = 0x2a, + DW_AT_start_scope = 0x2c, + DW_AT_bit_stride = 0x2e, + DW_AT_stride_size = 0x2e, + DW_AT_upper_bound = 0x2f, + DW_AT_abstract_origin = 0x31, + DW_AT_accessibility = 0x32, + DW_AT_address_class = 0x33, + DW_AT_artificial = 0x34, + DW_AT_base_types = 0x35, + DW_AT_calling_convention = 0x36, + DW_AT_count = 0x37, + DW_AT_data_member_location = 0x38, + DW_AT_decl_column = 0x39, + DW_AT_decl_file = 0x3a, + DW_AT_decl_line = 0x3b, + DW_AT_declaration = 0x3c, + DW_AT_discr_list = 0x3d, + DW_AT_encoding = 0x3e, + DW_AT_external = 0x3f, + DW_AT_frame_base = 0x40, + DW_AT_friend = 0x41, + DW_AT_identifier_case = 0x42, + DW_AT_macro_info = 0x43, + DW_AT_namelist_item = 0x44, + DW_AT_priority = 0x45, + DW_AT_segment = 0x46, + DW_AT_specification = 0x47, + DW_AT_static_link = 0x48, + DW_AT_type = 0x49, + DW_AT_use_location = 0x4a, + DW_AT_variable_parameter = 0x4b, + DW_AT_virtuality = 0x4c, + DW_AT_vtable_elem_location = 0x4d, + DW_AT_allocated = 0x4e, + DW_AT_associated = 0x4f, + DW_AT_data_location = 0x50, + DW_AT_byte_stride = 0x51, + DW_AT_stride = 0x51, + DW_AT_entry_pc = 0x52, + DW_AT_use_UTF8 = 0x53, + DW_AT_extension = 0x54, + DW_AT_ranges = 0x55, + DW_AT_trampoline = 0x56, + DW_AT_call_column = 0x57, + DW_AT_call_file = 0x58, + DW_AT_call_line = 0x59, + DW_AT_description = 0x5a, + DW_AT_binary_scale = 0x5b, + DW_AT_decimal_scale = 0x5c, + DW_AT_small = 0x5d, + DW_AT_decimal_sign = 0x5e, + DW_AT_digit_count = 0x5f, + DW_AT_picture_string = 0x60, + DW_AT_mutable = 0x61, + DW_AT_threads_scaled = 0x62, + DW_AT_explicit = 0x63, + DW_AT_object_pointer = 0x64, + DW_AT_endianity = 0x65, + DW_AT_elemental = 0x66, + DW_AT_pure = 0x67, + DW_AT_recursive = 0x68, + DW_AT_signature = 0x69, + DW_AT_main_subprogram = 0x6a, + DW_AT_data_bit_offset = 0x6b, + DW_AT_const_expr = 0x6c, + DW_AT_enum_class = 0x6d, + DW_AT_linkage_name = 0x6e, + + DW_AT_MIPS_fde = 0x2001, + DW_AT_MIPS_loop_begin = 0x2002, + DW_AT_MIPS_tail_loop_begin = 0x2003, + DW_AT_MIPS_epilog_begin = 0x2004, + DW_AT_MIPS_loop_unroll_factor = 0x2005, + DW_AT_MIPS_software_pipeline_depth = 0x2006, + DW_AT_MIPS_linkage_name = 0x2007, + DW_AT_MIPS_stride = 0x2008, + DW_AT_MIPS_abstract_name = 0x2009, + DW_AT_MIPS_clone_origin = 0x200a, + DW_AT_MIPS_has_inlines = 0x200b, + DW_AT_MIPS_stride_byte = 0x200c, + DW_AT_MIPS_stride_elem = 0x200d, + DW_AT_MIPS_ptr_dopetype = 0x200e, + DW_AT_MIPS_allocatable_dopetype = 0x200f, + DW_AT_MIPS_assumed_shape_dopetype = 0x2010, + DW_AT_MIPS_assumed_size = 0x2011, + + DW_AT_sf_names = 0x2101, + DW_AT_src_info = 0x2102, + DW_AT_mac_info = 0x2103, + DW_AT_src_coords = 0x2104, + DW_AT_body_begin = 0x2105, + DW_AT_body_end = 0x2106, + DW_AT_GNU_vector = 0x2107, + DW_AT_GNU_template_name = 0x2110, + + DW_AT_GNU_call_site_value = 0x2111, + DW_AT_GNU_call_site_data_value = 0x2112, + DW_AT_GNU_call_site_target = 0x2113, + DW_AT_GNU_call_site_target_clobbered = 0x2114, + DW_AT_GNU_tail_call = 0x2115, + DW_AT_GNU_all_tail_call_sites = 0x2116, + DW_AT_GNU_all_call_sites = 0x2117, + DW_AT_GNU_all_source_call_sites = 0x2118, + + DW_AT_APPLE_optimized = 0x3fe1, + DW_AT_APPLE_flags = 0x3fe2, + DW_AT_APPLE_isa = 0x3fe3, + DW_AT_APPLE_block = 0x3fe4, + DW_AT_APPLE_major_runtime_vers = 0x3fe5, + DW_AT_APPLE_runtime_class = 0x3fe6, + DW_AT_APPLE_omit_frame_ptr = 0x3fe7, + DW_AT_APPLE_property_name = 0x3fe8, + DW_AT_APPLE_property_getter = 0x3fe9, + DW_AT_APPLE_property_setter = 0x3fea, + DW_AT_APPLE_property_attribute = 0x3feb, + DW_AT_APPLE_objc_complete_type = 0x3fec, + DW_AT_APPLE_property = 0x3fed, + + _default_ = Pass, +) + + +ENUM_DW_FORM = dict( + DW_FORM_null = 0x00, + DW_FORM_addr = 0x01, + DW_FORM_block2 = 0x03, + DW_FORM_block4 = 0x04, + DW_FORM_data2 = 0x05, + DW_FORM_data4 = 0x06, + DW_FORM_data8 = 0x07, + DW_FORM_string = 0x08, + DW_FORM_block = 0x09, + DW_FORM_block1 = 0x0a, + DW_FORM_data1 = 0x0b, + DW_FORM_flag = 0x0c, + DW_FORM_sdata = 0x0d, + DW_FORM_strp = 0x0e, + DW_FORM_udata = 0x0f, + DW_FORM_ref_addr = 0x10, + DW_FORM_ref1 = 0x11, + DW_FORM_ref2 = 0x12, + DW_FORM_ref4 = 0x13, + DW_FORM_ref8 = 0x14, + DW_FORM_ref_udata = 0x15, + DW_FORM_indirect = 0x16, + DW_FORM_sec_offset = 0x17, + DW_FORM_exprloc = 0x18, + DW_FORM_flag_present = 0x19, + DW_FORM_ref_sig8 = 0x20, + + DW_FORM_GNU_strp_alt = 0x1f21, + DW_FORM_GNU_ref_alt = 0x1f20, + _default_ = Pass, +) + +# Inverse mapping for ENUM_DW_FORM +DW_FORM_raw2name = dict((v, k) for k, v in iteritems(ENUM_DW_FORM)) + diff --git a/tools/utils/contrib/elftools/dwarf/lineprogram.py b/tools/utils/contrib/elftools/dwarf/lineprogram.py new file mode 100755 index 0000000000..810e60398c --- /dev/null +++ b/tools/utils/contrib/elftools/dwarf/lineprogram.py @@ -0,0 +1,249 @@ +#------------------------------------------------------------------------------- +# elftools: dwarf/lineprogram.py +# +# DWARF line number program +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +import os +import copy +from collections import namedtuple + +from ..common.utils import struct_parse +from .constants import * + + +# LineProgramEntry - an entry in the line program. +# A line program is a sequence of encoded entries. Some of these entries add a +# new LineState (mapping between line and address), and some don't. +# +# command: +# The command/opcode - always numeric. For standard commands - it's the opcode +# that can be matched with one of the DW_LNS_* constants. For extended commands +# it's the extended opcode that can be matched with one of the DW_LNE_* +# constants. For special commands, it's the opcode itself. +# +# args: +# A list of decoded arguments of the command. +# +# is_extended: +# Since extended commands are encoded by a zero followed by an extended +# opcode, and these extended opcodes overlap with other opcodes, this +# flag is needed to mark that the command has an extended opcode. +# +# state: +# For commands that add a new state, it's the relevant LineState object. +# For commands that don't add a new state, it's None. +# +LineProgramEntry = namedtuple( + 'LineProgramEntry', 'command is_extended args state') + + +class LineState(object): + """ Represents a line program state (or a "row" in the matrix + describing debug location information for addresses). + The instance variables of this class are the "state machine registers" + described in section 6.2.2 of DWARFv3 + """ + def __init__(self, default_is_stmt): + self.address = 0 + self.file = 1 + self.line = 1 + self.column = 0 + self.is_stmt = default_is_stmt + self.basic_block = False + self.end_sequence = False + self.prologue_end = False + self.epilogue_begin = False + self.isa = 0 + + def __repr__(self): + a = ['\n' + + +class LineProgram(object): + """ Builds a "line table", which is essentially the matrix described + in section 6.2 of DWARFv3. It's a list of LineState objects, + sorted by increasing address, so it can be used to obtain the + state information for each address. + """ + def __init__(self, header, stream, structs, + program_start_offset, program_end_offset): + """ + header: + The header of this line program. Note: LineProgram may modify + its header by appending file entries if DW_LNE_define_file + instructions are encountered. + + stream: + The stream this program can be read from. + + structs: + A DWARFStructs instance suitable for this line program + + program_{start|end}_offset: + Offset in the debug_line section stream where this program + starts (the actual program, after the header), and where it + ends. + The actual range includes start but not end: [start, end - 1] + """ + self.stream = stream + self.header = header + self.structs = structs + self.program_start_offset = program_start_offset + self.program_end_offset = program_end_offset + self._decoded_entries = None + + def get_entries(self): + """ Get the decoded entries for this line program. Return a list of + LineProgramEntry objects. + Note that this contains more information than absolutely required + for the line table. The line table can be easily extracted from + the list of entries by looking only at entries with non-None + state. The extra information is mainly for the purposes of display + with readelf and debugging. + """ + if self._decoded_entries is None: + self._decoded_entries = self._decode_line_program() + return self._decoded_entries + + #------ PRIVATE ------# + + def __getitem__(self, name): + """ Implement dict-like access to header entries + """ + return self.header[name] + + def _decode_line_program(self): + entries = [] + state = LineState(self.header['default_is_stmt']) + + def add_entry_new_state(cmd, args, is_extended=False): + # Add an entry that sets a new state. + # After adding, clear some state registers. + entries.append(LineProgramEntry( + cmd, is_extended, args, copy.copy(state))) + state.basic_block = False + state.prologue_end = False + state.epilogue_begin = False + + def add_entry_old_state(cmd, args, is_extended=False): + # Add an entry that doesn't visibly set a new state + entries.append(LineProgramEntry(cmd, is_extended, args, None)) + + offset = self.program_start_offset + while offset < self.program_end_offset: + opcode = struct_parse( + self.structs.Dwarf_uint8(''), + self.stream, + offset) + + # As an exercise in avoiding premature optimization, if...elif + # chains are used here for standard and extended opcodes instead + # of dispatch tables. This keeps the code much cleaner. Besides, + # the majority of instructions in a typical program are special + # opcodes anyway. + if opcode >= self.header['opcode_base']: + # Special opcode (follow the recipe in 6.2.5.1) + adjusted_opcode = opcode - self['opcode_base'] + address_addend = ((adjusted_opcode // self['line_range']) * + self['minimum_instruction_length']) + state.address += address_addend + line_addend = (self['line_base'] + + adjusted_opcode % self['line_range']) + state.line += line_addend + add_entry_new_state(opcode, [line_addend, address_addend]) + elif opcode == 0: + # Extended opcode: start with a zero byte, followed by + # instruction size and the instruction itself. + inst_len = struct_parse(self.structs.Dwarf_uleb128(''), + self.stream) + ex_opcode = struct_parse(self.structs.Dwarf_uint8(''), + self.stream) + + if ex_opcode == DW_LNE_end_sequence: + state.end_sequence = True + add_entry_new_state(ex_opcode, [], is_extended=True) + # reset state + state = LineState(self.header['default_is_stmt']) + elif ex_opcode == DW_LNE_set_address: + operand = struct_parse(self.structs.Dwarf_target_addr(''), + self.stream) + state.address = operand + add_entry_old_state(ex_opcode, [operand], is_extended=True) + elif ex_opcode == DW_LNE_define_file: + operand = struct_parse( + self.structs.Dwarf_lineprog_file_entry, self.stream) + self['file_entry'].append(operand) + add_entry_old_state(ex_opcode, [operand], is_extended=True) + else: + # Unknown, but need to roll forward the stream because the + # length is specified. Seek forward inst_len - 1 because + # we've already read the extended opcode, which takes part + # in the length. + self.stream.seek(inst_len - 1, os.SEEK_CUR) + else: # 0 < opcode < opcode_base + # Standard opcode + if opcode == DW_LNS_copy: + add_entry_new_state(opcode, []) + elif opcode == DW_LNS_advance_pc: + operand = struct_parse(self.structs.Dwarf_uleb128(''), + self.stream) + address_addend = ( + operand * self.header['minimum_instruction_length']) + state.address += address_addend + add_entry_old_state(opcode, [address_addend]) + elif opcode == DW_LNS_advance_line: + operand = struct_parse(self.structs.Dwarf_sleb128(''), + self.stream) + state.line += operand + elif opcode == DW_LNS_set_file: + operand = struct_parse(self.structs.Dwarf_uleb128(''), + self.stream) + state.file = operand + add_entry_old_state(opcode, [operand]) + elif opcode == DW_LNS_set_column: + operand = struct_parse(self.structs.Dwarf_uleb128(''), + self.stream) + state.column = operand + add_entry_old_state(opcode, [operand]) + elif opcode == DW_LNS_negate_stmt: + state.is_stmt = not state.is_stmt + add_entry_old_state(opcode, []) + elif opcode == DW_LNS_set_basic_block: + state.basic_block = True + add_entry_old_state(opcode, []) + elif opcode == DW_LNS_const_add_pc: + adjusted_opcode = 255 - self['opcode_base'] + address_addend = ((adjusted_opcode // self['line_range']) * + self['minimum_instruction_length']) + state.address += address_addend + add_entry_old_state(opcode, [address_addend]) + elif opcode == DW_LNS_fixed_advance_pc: + operand = struct_parse(self.structs.Dwarf_uint16(''), + self.stream) + state.address += operand + add_entry_old_state(opcode, [operand]) + elif opcode == DW_LNS_set_prologue_end: + state.prologue_end = True + add_entry_old_state(opcode, []) + elif opcode == DW_LNS_set_epilogue_begin: + state.epilogue_begin = True + add_entry_old_state(opcode, []) + elif opcode == DW_LNS_set_isa: + operand = struct_parse(self.structs.Dwarf_uleb128(''), + self.stream) + state.isa = operand + add_entry_old_state(opcode, [operand]) + else: + dwarf_assert(False, 'Invalid standard line program opcode: %s' % ( + opcode,)) + offset = self.stream.tell() + return entries + diff --git a/tools/utils/contrib/elftools/dwarf/locationlists.py b/tools/utils/contrib/elftools/dwarf/locationlists.py new file mode 100755 index 0000000000..45aa36be0f --- /dev/null +++ b/tools/utils/contrib/elftools/dwarf/locationlists.py @@ -0,0 +1,72 @@ +#------------------------------------------------------------------------------- +# elftools: dwarf/locationlists.py +# +# DWARF location lists section decoding (.debug_loc) +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +import os +from collections import namedtuple + +from ..common.utils import struct_parse + + +LocationEntry = namedtuple('LocationEntry', 'begin_offset end_offset loc_expr') +BaseAddressEntry = namedtuple('BaseAddressEntry', 'base_address') + + +class LocationLists(object): + """ A single location list is a Python list consisting of LocationEntry or + BaseAddressEntry objects. + """ + def __init__(self, stream, structs): + self.stream = stream + self.structs = structs + self._max_addr = 2 ** (self.structs.address_size * 8) - 1 + + def get_location_list_at_offset(self, offset): + """ Get a location list at the given offset in the section. + """ + self.stream.seek(offset, os.SEEK_SET) + return self._parse_location_list_from_stream() + + def iter_location_lists(self): + """ Yield all location lists found in the section. + """ + # Just call _parse_location_list_from_stream until the stream ends + self.stream.seek(0, os.SEEK_END) + endpos = self.stream.tell() + + self.stream.seek(0, os.SEEK_SET) + while self.stream.tell() < endpos: + yield self._parse_location_list_from_stream() + + #------ PRIVATE ------# + + def _parse_location_list_from_stream(self): + lst = [] + while True: + begin_offset = struct_parse( + self.structs.Dwarf_target_addr(''), self.stream) + end_offset = struct_parse( + self.structs.Dwarf_target_addr(''), self.stream) + if begin_offset == 0 and end_offset == 0: + # End of list - we're done. + break + elif begin_offset == self._max_addr: + # Base address selection entry + lst.append(BaseAddressEntry(base_address=end_offset)) + else: + # Location list entry + expr_len = struct_parse( + self.structs.Dwarf_uint16(''), self.stream) + loc_expr = [struct_parse(self.structs.Dwarf_uint8(''), + self.stream) + for i in range(expr_len)] + lst.append(LocationEntry( + begin_offset=begin_offset, + end_offset=end_offset, + loc_expr=loc_expr)) + return lst + diff --git a/tools/utils/contrib/elftools/dwarf/ranges.py b/tools/utils/contrib/elftools/dwarf/ranges.py new file mode 100755 index 0000000000..9a216ee903 --- /dev/null +++ b/tools/utils/contrib/elftools/dwarf/ranges.py @@ -0,0 +1,68 @@ +#------------------------------------------------------------------------------- +# elftools: dwarf/ranges.py +# +# DWARF ranges section decoding (.debug_ranges) +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +import os +from collections import namedtuple + +from ..common.utils import struct_parse + + +RangeEntry = namedtuple('RangeEntry', 'begin_offset end_offset') +BaseAddressEntry = namedtuple('BaseAddressEntry', 'base_address') + + +class RangeLists(object): + """ A single range list is a Python list consisting of RangeEntry or + BaseAddressEntry objects. + """ + def __init__(self, stream, structs): + self.stream = stream + self.structs = structs + self._max_addr = 2 ** (self.structs.address_size * 8) - 1 + + def get_range_list_at_offset(self, offset): + """ Get a range list at the given offset in the section. + """ + self.stream.seek(offset, os.SEEK_SET) + return self._parse_range_list_from_stream() + + def iter_range_lists(self): + """ Yield all range lists found in the section. + """ + # Just call _parse_range_list_from_stream until the stream ends + self.stream.seek(0, os.SEEK_END) + endpos = self.stream.tell() + + self.stream.seek(0, os.SEEK_SET) + while self.stream.tell() < endpos: + yield self._parse_range_list_from_stream() + + #------ PRIVATE ------# + + def _parse_range_list_from_stream(self): + lst = [] + while True: + begin_offset = struct_parse( + self.structs.Dwarf_target_addr(''), self.stream) + end_offset = struct_parse( + self.structs.Dwarf_target_addr(''), self.stream) + if begin_offset == 0 and end_offset == 0: + # End of list - we're done. + break + elif begin_offset == self._max_addr: + # Base address selection entry + lst.append(BaseAddressEntry(base_address=end_offset)) + else: + # Range entry + lst.append(RangeEntry( + begin_offset=begin_offset, + end_offset=end_offset)) + return lst + + + diff --git a/tools/utils/contrib/elftools/dwarf/structs.py b/tools/utils/contrib/elftools/dwarf/structs.py new file mode 100755 index 0000000000..39e4815b2f --- /dev/null +++ b/tools/utils/contrib/elftools/dwarf/structs.py @@ -0,0 +1,339 @@ +#------------------------------------------------------------------------------- +# elftools: dwarf/structs.py +# +# Encapsulation of Construct structs for parsing DWARF, adjusted for correct +# endianness and word-size. +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +from ..construct import ( + UBInt8, UBInt16, UBInt32, UBInt64, ULInt8, ULInt16, ULInt32, ULInt64, + SBInt8, SBInt16, SBInt32, SBInt64, SLInt8, SLInt16, SLInt32, SLInt64, + Adapter, Struct, ConstructError, If, RepeatUntil, Field, Rename, Enum, + Array, PrefixedArray, CString, Embed, StaticField + ) +from ..common.construct_utils import RepeatUntilExcluding + +from .enums import * + + +class DWARFStructs(object): + """ Exposes Construct structs suitable for parsing information from DWARF + sections. Each compile unit in DWARF info can have its own structs + object. Keep in mind that these structs have to be given a name (by + calling them with a name) before being used for parsing (like other + Construct structs). Those that should be used without a name are marked + by (+). + + Accessible attributes (mostly as described in chapter 7 of the DWARF + spec v3): + + Dwarf_[u]int{8,16,32,64): + Data chunks of the common sizes + + Dwarf_offset: + 32-bit or 64-bit word, depending on dwarf_format + + Dwarf_target_addr: + 32-bit or 64-bit word, depending on address size + + Dwarf_initial_length: + "Initial length field" encoding + section 7.4 + + Dwarf_{u,s}leb128: + ULEB128 and SLEB128 variable-length encoding + + Dwarf_CU_header (+): + Compilation unit header + + Dwarf_abbrev_declaration (+): + Abbreviation table declaration - doesn't include the initial + code, only the contents. + + Dwarf_dw_form (+): + A dictionary mapping 'DW_FORM_*' keys into construct Structs + that parse such forms. These Structs have already been given + dummy names. + + Dwarf_lineprog_header (+): + Line program header + + Dwarf_lineprog_file_entry (+): + A single file entry in a line program header or instruction + + Dwarf_CIE_header (+): + A call-frame CIE + + Dwarf_FDE_header (+): + A call-frame FDE + + See also the documentation of public methods. + """ + def __init__(self, + little_endian, dwarf_format, address_size, dwarf_version=2): + """ dwarf_version: + Numeric DWARF version + + little_endian: + True if the file is little endian, False if big + + dwarf_format: + DWARF Format: 32 or 64-bit (see spec section 7.4) + + address_size: + Target machine address size, in bytes (4 or 8). (See spec + section 7.5.1) + """ + assert dwarf_format == 32 or dwarf_format == 64 + assert address_size == 8 or address_size == 4 + self.little_endian = little_endian + self.dwarf_format = dwarf_format + self.address_size = address_size + self.dwarf_version = dwarf_version + self._create_structs() + + def initial_length_field_size(self): + """ Size of an initial length field. + """ + return 4 if self.dwarf_format == 32 else 12 + + def _create_structs(self): + if self.little_endian: + self.Dwarf_uint8 = ULInt8 + self.Dwarf_uint16 = ULInt16 + self.Dwarf_uint32 = ULInt32 + self.Dwarf_uint64 = ULInt64 + self.Dwarf_offset = ULInt32 if self.dwarf_format == 32 else ULInt64 + self.Dwarf_target_addr = ( + ULInt32 if self.address_size == 4 else ULInt64) + self.Dwarf_int8 = SLInt8 + self.Dwarf_int16 = SLInt16 + self.Dwarf_int32 = SLInt32 + self.Dwarf_int64 = SLInt64 + else: + self.Dwarf_uint8 = UBInt8 + self.Dwarf_uint16 = UBInt16 + self.Dwarf_uint32 = UBInt32 + self.Dwarf_uint64 = UBInt64 + self.Dwarf_offset = UBInt32 if self.dwarf_format == 32 else UBInt64 + self.Dwarf_target_addr = ( + UBInt32 if self.address_size == 4 else UBInt64) + self.Dwarf_int8 = SBInt8 + self.Dwarf_int16 = SBInt16 + self.Dwarf_int32 = SBInt32 + self.Dwarf_int64 = SBInt64 + + self._create_initial_length() + self._create_leb128() + self._create_cu_header() + self._create_abbrev_declaration() + self._create_dw_form() + self._create_lineprog_header() + self._create_callframe_entry_headers() + + def _create_initial_length(self): + def _InitialLength(name): + # Adapts a Struct that parses forward a full initial length field. + # Only if the first word is the continuation value, the second + # word is parsed from the stream. + # + return _InitialLengthAdapter( + Struct(name, + self.Dwarf_uint32('first'), + If(lambda ctx: ctx.first == 0xFFFFFFFF, + self.Dwarf_uint64('second'), + elsevalue=None))) + self.Dwarf_initial_length = _InitialLength + + def _create_leb128(self): + self.Dwarf_uleb128 = _ULEB128 + self.Dwarf_sleb128 = _SLEB128 + + def _create_cu_header(self): + self.Dwarf_CU_header = Struct('Dwarf_CU_header', + self.Dwarf_initial_length('unit_length'), + self.Dwarf_uint16('version'), + self.Dwarf_offset('debug_abbrev_offset'), + self.Dwarf_uint8('address_size')) + + def _create_abbrev_declaration(self): + self.Dwarf_abbrev_declaration = Struct('Dwarf_abbrev_entry', + Enum(self.Dwarf_uleb128('tag'), **ENUM_DW_TAG), + Enum(self.Dwarf_uint8('children_flag'), **ENUM_DW_CHILDREN), + RepeatUntilExcluding( + lambda obj, ctx: + obj.name == 'DW_AT_null' and obj.form == 'DW_FORM_null', + Struct('attr_spec', + Enum(self.Dwarf_uleb128('name'), **ENUM_DW_AT), + Enum(self.Dwarf_uleb128('form'), **ENUM_DW_FORM)))) + + def _create_dw_form(self): + self.Dwarf_dw_form = dict( + DW_FORM_addr=self.Dwarf_target_addr(''), + + DW_FORM_block1=self._make_block_struct(self.Dwarf_uint8), + DW_FORM_block2=self._make_block_struct(self.Dwarf_uint16), + DW_FORM_block4=self._make_block_struct(self.Dwarf_uint32), + DW_FORM_block=self._make_block_struct(self.Dwarf_uleb128), + + # All DW_FORM_data forms are assumed to be unsigned + DW_FORM_data1=self.Dwarf_uint8(''), + DW_FORM_data2=self.Dwarf_uint16(''), + DW_FORM_data4=self.Dwarf_uint32(''), + DW_FORM_data8=self.Dwarf_uint64(''), + DW_FORM_sdata=self.Dwarf_sleb128(''), + DW_FORM_udata=self.Dwarf_uleb128(''), + + DW_FORM_string=CString(''), + DW_FORM_strp=self.Dwarf_offset(''), + DW_FORM_flag=self.Dwarf_uint8(''), + + DW_FORM_ref1=self.Dwarf_uint8(''), + DW_FORM_ref2=self.Dwarf_uint16(''), + DW_FORM_ref4=self.Dwarf_uint32(''), + DW_FORM_ref8=self.Dwarf_uint64(''), + DW_FORM_ref_udata=self.Dwarf_uleb128(''), + DW_FORM_ref_addr=self.Dwarf_offset(''), + + DW_FORM_indirect=self.Dwarf_uleb128(''), + + # New forms in DWARFv4 + DW_FORM_flag_present = StaticField('', 0), + DW_FORM_sec_offset = self.Dwarf_offset(''), + DW_FORM_exprloc = self._make_block_struct(self.Dwarf_uleb128), + DW_FORM_ref_sig8 = self.Dwarf_offset(''), + + DW_FORM_GNU_strp_alt=self.Dwarf_offset(''), + DW_FORM_GNU_ref_alt=self.Dwarf_offset(''), + DW_AT_GNU_all_call_sites=self.Dwarf_uleb128(''), + ) + + def _create_lineprog_header(self): + # A file entry is terminated by a NULL byte, so we don't want to parse + # past it. Therefore an If is used. + self.Dwarf_lineprog_file_entry = Struct('file_entry', + CString('name'), + If(lambda ctx: len(ctx.name) != 0, + Embed(Struct('', + self.Dwarf_uleb128('dir_index'), + self.Dwarf_uleb128('mtime'), + self.Dwarf_uleb128('length'))))) + + self.Dwarf_lineprog_header = Struct('Dwarf_lineprog_header', + self.Dwarf_initial_length('unit_length'), + self.Dwarf_uint16('version'), + self.Dwarf_offset('header_length'), + self.Dwarf_uint8('minimum_instruction_length'), + self.Dwarf_uint8('default_is_stmt'), + self.Dwarf_int8('line_base'), + self.Dwarf_uint8('line_range'), + self.Dwarf_uint8('opcode_base'), + Array(lambda ctx: ctx['opcode_base'] - 1, + self.Dwarf_uint8('standard_opcode_lengths')), + RepeatUntilExcluding( + lambda obj, ctx: obj == b'', + CString('include_directory')), + RepeatUntilExcluding( + lambda obj, ctx: len(obj.name) == 0, + self.Dwarf_lineprog_file_entry), + ) + + def _create_callframe_entry_headers(self): + # The CIE header was modified in DWARFv4. + if self.dwarf_version == 4: + self.Dwarf_CIE_header = Struct('Dwarf_CIE_header', + self.Dwarf_initial_length('length'), + self.Dwarf_offset('CIE_id'), + self.Dwarf_uint8('version'), + CString('augmentation'), + self.Dwarf_uint8('address_size'), + self.Dwarf_uint8('segment_size'), + self.Dwarf_uleb128('code_alignment_factor'), + self.Dwarf_sleb128('data_alignment_factor'), + self.Dwarf_uleb128('return_address_register')) + else: + self.Dwarf_CIE_header = Struct('Dwarf_CIE_header', + self.Dwarf_initial_length('length'), + self.Dwarf_offset('CIE_id'), + self.Dwarf_uint8('version'), + CString('augmentation'), + self.Dwarf_uleb128('code_alignment_factor'), + self.Dwarf_sleb128('data_alignment_factor'), + self.Dwarf_uleb128('return_address_register')) + + self.Dwarf_FDE_header = Struct('Dwarf_FDE_header', + self.Dwarf_initial_length('length'), + self.Dwarf_offset('CIE_pointer'), + self.Dwarf_target_addr('initial_location'), + self.Dwarf_target_addr('address_range')) + + def _make_block_struct(self, length_field): + """ Create a struct for DW_FORM_block + """ + return PrefixedArray( + subcon=self.Dwarf_uint8('elem'), + length_field=length_field('')) + + +class _InitialLengthAdapter(Adapter): + """ A standard Construct adapter that expects a sub-construct + as a struct with one or two values (first, second). + """ + def _decode(self, obj, context): + if obj.first < 0xFFFFFF00: + return obj.first + else: + if obj.first == 0xFFFFFFFF: + return obj.second + else: + raise ConstructError("Failed decoding initial length for %X" % ( + obj.first)) + + +def _LEB128_reader(): + """ Read LEB128 variable-length data from the stream. The data is terminated + by a byte with 0 in its highest bit. + """ + return RepeatUntil( + lambda obj, ctx: ord(obj) < 0x80, + Field(None, 1)) + + +class _ULEB128Adapter(Adapter): + """ An adapter for ULEB128, given a sequence of bytes in a sub-construct. + """ + def _decode(self, obj, context): + value = 0 + for b in reversed(obj): + value = (value << 7) + (ord(b) & 0x7F) + return value + + +class _SLEB128Adapter(Adapter): + """ An adapter for SLEB128, given a sequence of bytes in a sub-construct. + """ + def _decode(self, obj, context): + value = 0 + for b in reversed(obj): + value = (value << 7) + (ord(b) & 0x7F) + if ord(obj[-1]) & 0x40: + # negative -> sign extend + # + value |= - (1 << (7 * len(obj))) + return value + + +def _ULEB128(name): + """ A construct creator for ULEB128 encoding. + """ + return Rename(name, _ULEB128Adapter(_LEB128_reader())) + + +def _SLEB128(name): + """ A construct creator for SLEB128 encoding. + """ + return Rename(name, _SLEB128Adapter(_LEB128_reader())) + + diff --git a/tools/utils/contrib/elftools/elf/__init__.py b/tools/utils/contrib/elftools/elf/__init__.py new file mode 100755 index 0000000000..e69de29bb2 diff --git a/tools/utils/contrib/elftools/elf/constants.py b/tools/utils/contrib/elftools/elf/constants.py new file mode 100755 index 0000000000..df6e0af50e --- /dev/null +++ b/tools/utils/contrib/elftools/elf/constants.py @@ -0,0 +1,108 @@ +#------------------------------------------------------------------------------- +# elftools: elf/constants.py +# +# Constants and flags, placed into classes for namespacing +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- + +class E_FLAGS(object): + """ Flag values for the e_flags field of the ELF header + """ + EF_ARM_EABIMASK=0xFF000000 + EF_ARM_EABI_VER1=0x01000000 + EF_ARM_EABI_VER2=0x02000000 + EF_ARM_EABI_VER3=0x03000000 + EF_ARM_EABI_VER4=0x04000000 + EF_ARM_EABI_VER5=0x05000000 + EF_ARM_GCCMASK=0x00400FFF + EF_ARM_HASENTRY=0x02 + EF_ARM_SYMSARESORTED=0x04 + EF_ARM_DYNSYMSUSESEGIDX=0x8 + EF_ARM_MAPSYMSFIRST=0x10 + EF_ARM_LE8=0x00400000 + EF_ARM_BE8=0x00800000 + EF_ARM_ABI_FLOAT_SOFT=0x00000200 + EF_ARM_ABI_FLOAT_HARD=0x00000400 + + EF_MIPS_NOREORDER=1 + EF_MIPS_PIC=2 + EF_MIPS_CPIC=4 + EF_MIPS_XGOT=8 + EF_MIPS_64BIT_WHIRL=16 + EF_MIPS_ABI2=32 + EF_MIPS_ABI_ON32=64 + EF_MIPS_NAN2008=1024 + EF_MIPS_ARCH=0xf0000000 + EF_MIPS_ARCH_1=0x00000000 + EF_MIPS_ARCH_2=0x10000000 + EF_MIPS_ARCH_3=0x20000000 + EF_MIPS_ARCH_4=0x30000000 + EF_MIPS_ARCH_5=0x40000000 + EF_MIPS_ARCH_32=0x50000000 + EF_MIPS_ARCH_64=0x60000000 + EF_MIPS_ARCH_32R2=0x70000000 + EF_MIPS_ARCH_64R2=0x80000000 + +class SHN_INDICES(object): + """ Special section indices + """ + SHN_UNDEF=0 + SHN_LORESERVE=0xff00 + SHN_LOPROC=0xff00 + SHN_HIPROC=0xff1f + SHN_ABS=0xfff1 + SHN_COMMON=0xfff2 + SHN_HIRESERVE=0xffff + + +class SH_FLAGS(object): + """ Flag values for the sh_flags field of section headers + """ + SHF_WRITE=0x1 + SHF_ALLOC=0x2 + SHF_EXECINSTR=0x4 + SHF_MERGE=0x10 + SHF_STRINGS=0x20 + SHF_INFO_LINK=0x40 + SHF_LINK_ORDER=0x80 + SHF_OS_NONCONFORMING=0x100 + SHF_GROUP=0x200 + SHF_TLS=0x400 + SHF_MASKOS=0x0ff00000 + SHF_EXCLUDE=0x80000000 + SHF_MASKPROC=0xf0000000 + + +class P_FLAGS(object): + """ Flag values for the p_flags field of program headers + """ + PF_X=0x1 + PF_W=0x2 + PF_R=0x4 + PF_MASKOS=0x00FF0000 + PF_MASKPROC=0xFF000000 + + +# symbol info flags for entries +# in the .SUNW_syminfo section +class SUNW_SYMINFO_FLAGS(object): + """ Flags for the si_flags field of entries + in the .SUNW_syminfo section + """ + SYMINFO_FLG_DIRECT=0x1 + SYMINFO_FLG_FILTER=0x2 + SYMINFO_FLG_COPY=0x4 + SYMINFO_FLG_LAZYLOAD=0x8 + SYMINFO_FLG_DIRECTBIND=0x10 + SYMINFO_FLG_NOEXTDIRECT=0x20 + SYMINFO_FLG_AUXILIARY=0x40 + SYMINFO_FLG_INTERPOSE=0x80 + SYMINFO_FLG_CAP=0x100 + SYMINFO_FLG_DEFERRED=0x200 + +class VER_FLAGS(object): + VER_FLG_BASE=0x1 + VER_FLG_WEAK=0x2 + VER_FLG_INFO=0x4 diff --git a/tools/utils/contrib/elftools/elf/descriptions.py b/tools/utils/contrib/elftools/elf/descriptions.py new file mode 100755 index 0000000000..f085b8786d --- /dev/null +++ b/tools/utils/contrib/elftools/elf/descriptions.py @@ -0,0 +1,405 @@ +#------------------------------------------------------------------------------- +# elftools: elf/descriptions.py +# +# Textual descriptions of the various enums and flags of ELF +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +from .enums import ( + ENUM_D_TAG, ENUM_E_VERSION, ENUM_P_TYPE, ENUM_SH_TYPE, + ENUM_RELOC_TYPE_i386, ENUM_RELOC_TYPE_x64, + ENUM_RELOC_TYPE_ARM, ENUM_RELOC_TYPE_AARCH64, ENUM_RELOC_TYPE_MIPS) +from .constants import P_FLAGS, SH_FLAGS, SUNW_SYMINFO_FLAGS, VER_FLAGS +from ..common.py3compat import iteritems + + +def describe_ei_class(x): + return _DESCR_EI_CLASS.get(x, _unknown) + +def describe_ei_data(x): + return _DESCR_EI_DATA.get(x, _unknown) + +def describe_ei_version(x): + s = '%d' % ENUM_E_VERSION[x] + if x == 'EV_CURRENT': + s += ' (current)' + return s + +def describe_ei_osabi(x): + return _DESCR_EI_OSABI.get(x, _unknown) + +def describe_e_type(x): + return _DESCR_E_TYPE.get(x, _unknown) + +def describe_e_machine(x): + return _DESCR_E_MACHINE.get(x, _unknown) + +def describe_e_version_numeric(x): + return '0x%x' % ENUM_E_VERSION[x] + +def describe_p_type(x): + if x in _DESCR_P_TYPE: + return _DESCR_P_TYPE.get(x) + elif x >= ENUM_P_TYPE['PT_LOOS'] and x <= ENUM_P_TYPE['PT_HIOS']: + return 'LOOS+%lx' % (x - ENUM_P_TYPE['PT_LOOS']) + else: + return _unknown + +def describe_p_flags(x): + s = '' + for flag in (P_FLAGS.PF_R, P_FLAGS.PF_W, P_FLAGS.PF_X): + s += _DESCR_P_FLAGS[flag] if (x & flag) else ' ' + return s + +def describe_sh_type(x): + if x in _DESCR_SH_TYPE: + return _DESCR_SH_TYPE.get(x) + elif x >= ENUM_SH_TYPE['SHT_LOOS'] and x < ENUM_SH_TYPE['SHT_GNU_versym']: + return 'loos+%lx' % (x - ENUM_SH_TYPE['SHT_LOOS']) + else: + return _unknown + +def describe_sh_flags(x): + s = '' + for flag in ( + SH_FLAGS.SHF_WRITE, SH_FLAGS.SHF_ALLOC, SH_FLAGS.SHF_EXECINSTR, + SH_FLAGS.SHF_MERGE, SH_FLAGS.SHF_STRINGS, SH_FLAGS.SHF_INFO_LINK, + SH_FLAGS.SHF_LINK_ORDER, SH_FLAGS.SHF_OS_NONCONFORMING, + SH_FLAGS.SHF_GROUP, SH_FLAGS.SHF_TLS, SH_FLAGS.SHF_EXCLUDE): + s += _DESCR_SH_FLAGS[flag] if (x & flag) else '' + return s + +def describe_symbol_type(x): + return _DESCR_ST_INFO_TYPE.get(x, _unknown) + +def describe_symbol_bind(x): + return _DESCR_ST_INFO_BIND.get(x, _unknown) + +def describe_symbol_visibility(x): + return _DESCR_ST_VISIBILITY.get(x, _unknown) + +def describe_symbol_shndx(x): + return _DESCR_ST_SHNDX.get(x, '%3s' % x) + +def describe_reloc_type(x, elffile): + arch = elffile.get_machine_arch() + if arch == 'x86': + return _DESCR_RELOC_TYPE_i386.get(x, _unknown) + elif arch == 'x64': + return _DESCR_RELOC_TYPE_x64.get(x, _unknown) + elif arch == 'ARM': + return _DESCR_RELOC_TYPE_ARM.get(x, _unknown) + elif arch == 'AArch64': + return _DESCR_RELOC_TYPE_AARCH64.get(x, _unknown) + elif arch == 'MIPS': + return _DESCR_RELOC_TYPE_MIPS.get(x, _unknown) + else: + return 'unrecognized: %-7x' % (x & 0xFFFFFFFF) + +def describe_dyn_tag(x): + return _DESCR_D_TAG.get(x, _unknown) + + +def describe_syminfo_flags(x): + return ''.join(_DESCR_SYMINFO_FLAGS[flag] for flag in ( + SUNW_SYMINFO_FLAGS.SYMINFO_FLG_CAP, + SUNW_SYMINFO_FLAGS.SYMINFO_FLG_DIRECT, + SUNW_SYMINFO_FLAGS.SYMINFO_FLG_FILTER, + SUNW_SYMINFO_FLAGS.SYMINFO_FLG_AUXILIARY, + SUNW_SYMINFO_FLAGS.SYMINFO_FLG_DIRECTBIND, + SUNW_SYMINFO_FLAGS.SYMINFO_FLG_COPY, + SUNW_SYMINFO_FLAGS.SYMINFO_FLG_LAZYLOAD, + SUNW_SYMINFO_FLAGS.SYMINFO_FLG_NOEXTDIRECT, + SUNW_SYMINFO_FLAGS.SYMINFO_FLG_INTERPOSE, + SUNW_SYMINFO_FLAGS.SYMINFO_FLG_DEFERRED) if x & flag) + +def describe_symbol_boundto(x): + return _DESCR_SYMINFO_BOUNDTO.get(x, '%3s' % x) + +def describe_ver_flags(x): + return ' | '.join(_DESCR_VER_FLAGS[flag] for flag in ( + VER_FLAGS.VER_FLG_WEAK, + VER_FLAGS.VER_FLG_BASE, + VER_FLAGS.VER_FLG_INFO) if x & flag) + +def describe_note(x): + n_desc = x['n_desc'] + desc = '' + if x['n_type'] == 'NT_GNU_ABI_TAG': + desc = '\n OS: %s, ABI: %d.%d.%d' % ( + _DESCR_NOTE_ABI_TAG_OS.get(n_desc['abi_os'], _unknown), + n_desc['abi_major'], n_desc['abi_minor'], n_desc['abi_tiny']) + elif x['n_type'] == 'NT_GNU_BUILD_ID': + desc = '\n Build ID: %s' % (n_desc) + + note_type = (x['n_type'] if isinstance(x['n_type'], str) + else 'Unknown note type:') + note_type_desc = ('0x%.8x' % x['n_type'] if isinstance(x['n_type'], int) else + _DESCR_NOTE_N_TYPE.get(x['n_type'], _unknown)) + return '%s (%s)%s' % (note_type, note_type_desc, desc) + +#------------------------------------------------------------------------------- +_unknown = '' + + +_DESCR_EI_CLASS = dict( + ELFCLASSNONE='none', + ELFCLASS32='ELF32', + ELFCLASS64='ELF64', +) + +_DESCR_EI_DATA = dict( + ELFDATANONE='none', + ELFDATA2LSB="2's complement, little endian", + ELFDATA2MSB="2's complement, big endian", +) + +_DESCR_EI_OSABI = dict( + ELFOSABI_SYSV='UNIX - System V', + ELFOSABI_HPUX='UNIX - HP-UX', + ELFOSABI_NETBSD='UNIX - NetBSD', + ELFOSABI_LINUX='UNIX - Linux', + ELFOSABI_HURD='UNIX - GNU/Hurd', + ELFOSABI_SOLARIS='UNIX - Solaris', + ELFOSABI_AIX='UNIX - AIX', + ELFOSABI_IRIX='UNIX - IRIX', + ELFOSABI_FREEBSD='UNIX - FreeBSD', + ELFOSABI_TRU64='UNIX - TRU64', + ELFOSABI_MODESTO='Novell - Modesto', + ELFOSABI_OPENBSD='UNIX - OpenBSD', + ELFOSABI_OPENVMS='VMS - OpenVMS', + ELFOSABI_NSK='HP - Non-Stop Kernel', + ELFOSABI_AROS='AROS', + ELFOSABI_ARM='ARM', + ELFOSABI_STANDALONE='Standalone App', +) + +_DESCR_E_TYPE = dict( + ET_NONE='NONE (None)', + ET_REL='REL (Relocatable file)', + ET_EXEC='EXEC (Executable file)', + ET_DYN='DYN (Shared object file)', + ET_CORE='CORE (Core file)', + PROC_SPECIFIC='Processor Specific', +) + +_DESCR_E_MACHINE = dict( + EM_NONE='None', + EM_M32='WE32100', + EM_SPARC='Sparc', + EM_386='Intel 80386', + EM_68K='MC68000', + EM_88K='MC88000', + EM_860='Intel 80860', + EM_MIPS='MIPS R3000', + EM_S370='IBM System/370', + EM_MIPS_RS4_BE='MIPS 4000 big-endian', + EM_IA_64='Intel IA-64', + EM_X86_64='Advanced Micro Devices X86-64', + EM_AVR='Atmel AVR 8-bit microcontroller', + EM_ARM='ARM', + EM_AARCH64='AArch64', + EM_BLAFKIN='Analog Devices Blackfin', + RESERVED='RESERVED', +) + +_DESCR_P_TYPE = dict( + PT_NULL='NULL', + PT_LOAD='LOAD', + PT_DYNAMIC='DYNAMIC', + PT_INTERP='INTERP', + PT_NOTE='NOTE', + PT_SHLIB='SHLIB', + PT_PHDR='PHDR', + PT_GNU_EH_FRAME='GNU_EH_FRAME', + PT_GNU_STACK='GNU_STACK', + PT_GNU_RELRO='GNU_RELRO', + PT_ARM_ARCHEXT='ARM_ARCHEXT', + PT_ARM_EXIDX='ARM_EXIDX', + PT_ARM_UNWIND='ARM_UNWIND', + PT_AARCH64_ARCHEXT='AARCH64_ARCHEXT', + PT_AARCH64_UNWIND='AARCH64_UNWIND', +) + +_DESCR_P_FLAGS = { + P_FLAGS.PF_X: 'E', + P_FLAGS.PF_R: 'R', + P_FLAGS.PF_W: 'W', +} + +_DESCR_SH_TYPE = dict( + SHT_NULL='NULL', + SHT_PROGBITS='PROGBITS', + SHT_SYMTAB='SYMTAB', + SHT_STRTAB='STRTAB', + SHT_RELA='RELA', + SHT_HASH='HASH', + SHT_DYNAMIC='DYNAMIC', + SHT_NOTE='NOTE', + SHT_NOBITS='NOBITS', + SHT_REL='REL', + SHT_SHLIB='SHLIB', + SHT_DYNSYM='DYNSYM', + SHT_INIT_ARRAY='INIT_ARRAY', + SHT_FINI_ARRAY='FINI_ARRAY', + SHT_PREINIT_ARRAY='PREINIT_ARRAY', + SHT_GNU_HASH='GNU_HASH', + SHT_GROUP='GROUP', + SHT_SYMTAB_SHNDX='SYMTAB SECTION INDICIES', + SHT_GNU_verdef='VERDEF', + SHT_GNU_verneed='VERNEED', + SHT_GNU_versym='VERSYM', + SHT_GNU_LIBLIST='GNU_LIBLIST', + SHT_ARM_EXIDX='ARM_EXIDX', + SHT_ARM_PREEMPTMAP='ARM_PREEMPTMAP', + SHT_ARM_ATTRIBUTES='ARM_ATTRIBUTES', + SHT_ARM_DEBUGOVERLAY='ARM_DEBUGOVERLAY', + SHT_MIPS_LIBLIST='MIPS_LIBLIST', + SHT_MIPS_DEBUG='MIPS_DEBUG', + SHT_MIPS_REGINFO='MIPS_REGINFO', + SHT_MIPS_PACKAGE='MIPS_PACKAGE', + SHT_MIPS_PACKSYM='MIPS_PACKSYM', + SHT_MIPS_RELD='MIPS_RELD', + SHT_MIPS_IFACE='MIPS_IFACE', + SHT_MIPS_CONTENT='MIPS_CONTENT', + SHT_MIPS_OPTIONS='MIPS_OPTIONS', + SHT_MIPS_SHDR='MIPS_SHDR', + SHT_MIPS_FDESC='MIPS_FDESC', + SHT_MIPS_EXTSYM='MIPS_EXTSYM', + SHT_MIPS_DENSE='MIPS_DENSE', + SHT_MIPS_PDESC='MIPS_PDESC', + SHT_MIPS_LOCSYM='MIPS_LOCSYM', + SHT_MIPS_AUXSYM='MIPS_AUXSYM', + SHT_MIPS_OPTSYM='MIPS_OPTSYM', + SHT_MIPS_LOCSTR='MIPS_LOCSTR', + SHT_MIPS_LINE='MIPS_LINE', + SHT_MIPS_RFDESC='MIPS_RFDESC', + SHT_MIPS_DELTASYM='MIPS_DELTASYM', + SHT_MIPS_DELTAINST='MIPS_DELTAINST', + SHT_MIPS_DELTACLASS='MIPS_DELTACLASS', + SHT_MIPS_DWARF='MIPS_DWARF', + SHT_MIPS_DELTADECL='MIPS_DELTADECL', + SHT_MIPS_SYMBOL_LIB='MIPS_SYMBOL_LIB', + SHT_MIPS_EVENTS='MIPS_EVENTS', + SHT_MIPS_TRANSLATE='MIPS_TRANSLATE', + SHT_MIPS_PIXIE='MIPS_PIXIE', + SHT_MIPS_XLATE='MIPS_XLATE', + SHT_MIPS_XLATE_DEBUG='MIPS_XLATE_DEBUG', + SHT_MIPS_WHIRL='MIPS_WHIRL', + SHT_MIPS_EH_REGION='MIPS_EH_REGION', + SHT_MIPS_XLATE_OLD='MIPS_XLATE_OLD', + SHT_MIPS_PDR_EXCEPTION='MIPS_PDR_EXCEPTION', +) + +_DESCR_SH_FLAGS = { + SH_FLAGS.SHF_WRITE: 'W', + SH_FLAGS.SHF_ALLOC: 'A', + SH_FLAGS.SHF_EXECINSTR: 'X', + SH_FLAGS.SHF_MERGE: 'M', + SH_FLAGS.SHF_STRINGS: 'S', + SH_FLAGS.SHF_INFO_LINK: 'I', + SH_FLAGS.SHF_LINK_ORDER: 'L', + SH_FLAGS.SHF_OS_NONCONFORMING: 'O', + SH_FLAGS.SHF_GROUP: 'G', + SH_FLAGS.SHF_TLS: 'T', + SH_FLAGS.SHF_EXCLUDE: 'E', +} + +_DESCR_ST_INFO_TYPE = dict( + STT_NOTYPE='NOTYPE', + STT_OBJECT='OBJECT', + STT_FUNC='FUNC', + STT_SECTION='SECTION', + STT_FILE='FILE', + STT_COMMON='COMMON', + STT_TLS='TLS', + STT_NUM='NUM', + STT_RELC='RELC', + STT_SRELC='SRELC', +) + +_DESCR_ST_INFO_BIND = dict( + STB_LOCAL='LOCAL', + STB_GLOBAL='GLOBAL', + STB_WEAK='WEAK', +) + +_DESCR_ST_VISIBILITY = dict( + STV_DEFAULT='DEFAULT', + STV_INTERNAL='INTERNAL', + STV_HIDDEN='HIDDEN', + STV_PROTECTED='PROTECTED', + STV_EXPORTED='EXPORTED', + STV_SINGLETON='SINGLETON', + STV_ELIMINATE='ELIMINATE', +) + +_DESCR_ST_SHNDX = dict( + SHN_UNDEF='UND', + SHN_ABS='ABS', + SHN_COMMON='COM', +) + +_DESCR_SYMINFO_FLAGS = { + SUNW_SYMINFO_FLAGS.SYMINFO_FLG_DIRECT: 'D', + SUNW_SYMINFO_FLAGS.SYMINFO_FLG_DIRECTBIND: 'B', + SUNW_SYMINFO_FLAGS.SYMINFO_FLG_COPY: 'C', + SUNW_SYMINFO_FLAGS.SYMINFO_FLG_LAZYLOAD: 'L', + SUNW_SYMINFO_FLAGS.SYMINFO_FLG_NOEXTDIRECT: 'N', + SUNW_SYMINFO_FLAGS.SYMINFO_FLG_AUXILIARY: 'A', + SUNW_SYMINFO_FLAGS.SYMINFO_FLG_FILTER: 'F', + SUNW_SYMINFO_FLAGS.SYMINFO_FLG_INTERPOSE: 'I', + SUNW_SYMINFO_FLAGS.SYMINFO_FLG_CAP: 'S', + SUNW_SYMINFO_FLAGS.SYMINFO_FLG_DEFERRED: 'P', +} + +_DESCR_SYMINFO_BOUNDTO = dict( + SYMINFO_BT_SELF='', + SYMINFO_BT_PARENT='', + SYMINFO_BT_NONE='', + SYMINFO_BT_EXTERN='', +) + +_DESCR_VER_FLAGS = { + 0: '', + VER_FLAGS.VER_FLG_BASE: 'BASE', + VER_FLAGS.VER_FLG_WEAK: 'WEAK', + VER_FLAGS.VER_FLG_INFO: 'INFO', +} + +# PT_NOTE section types +_DESCR_NOTE_N_TYPE = dict( + NT_GNU_ABI_TAG='ABI version tag', + NT_GNU_HWCAP='DSO-supplied software HWCAP info', + NT_GNU_BUILD_ID='unique build ID bitstring', + NT_GNU_GOLD_VERSION='gold version', +) + +# Values in GNU .note.ABI-tag notes (n_type=='NT_GNU_ABI_TAG') +_DESCR_NOTE_ABI_TAG_OS = dict( + ELF_NOTE_OS_LINUX='Linux', + ELF_NOTE_OS_GNU='GNU', + ELF_NOTE_OS_SOLARIS2='Solaris 2', + ELF_NOTE_OS_FREEBSD='FreeBSD', + ELF_NOTE_OS_NETBSD='NetBSD', + ELF_NOTE_OS_SYLLABLE='Syllable', +) + +_DESCR_RELOC_TYPE_i386 = dict( + (v, k) for k, v in iteritems(ENUM_RELOC_TYPE_i386)) + +_DESCR_RELOC_TYPE_x64 = dict( + (v, k) for k, v in iteritems(ENUM_RELOC_TYPE_x64)) + +_DESCR_RELOC_TYPE_ARM = dict( + (v, k) for k, v in iteritems(ENUM_RELOC_TYPE_ARM)) + +_DESCR_RELOC_TYPE_AARCH64 = dict( + (v, k) for k, v in iteritems(ENUM_RELOC_TYPE_AARCH64)) + +_DESCR_RELOC_TYPE_MIPS = dict( + (v, k) for k, v in iteritems(ENUM_RELOC_TYPE_MIPS)) + +_DESCR_D_TAG = dict( + (v, k) for k, v in iteritems(ENUM_D_TAG)) diff --git a/tools/utils/contrib/elftools/elf/dynamic.py b/tools/utils/contrib/elftools/elf/dynamic.py new file mode 100755 index 0000000000..0b3e3e99b9 --- /dev/null +++ b/tools/utils/contrib/elftools/elf/dynamic.py @@ -0,0 +1,234 @@ +#------------------------------------------------------------------------------- +# elftools: elf/dynamic.py +# +# ELF Dynamic Tags +# +# Mike Frysinger (vapier@gentoo.org) +# This code is in the public domain +#------------------------------------------------------------------------------- +import itertools + +from .sections import Section, Symbol +from .segments import Segment +from ..common.exceptions import ELFError +from ..common.utils import struct_parse, parse_cstring_from_stream + + +class _DynamicStringTable(object): + """ Bare string table based on values found via ELF dynamic tags and + loadable segments only. Good enough for get_string() only. + """ + def __init__(self, stream, table_offset): + self._stream = stream + self._table_offset = table_offset + + def get_string(self, offset): + """ Get the string stored at the given offset in this string table. + """ + return parse_cstring_from_stream(self._stream, + self._table_offset + offset) + + +class DynamicTag(object): + """ Dynamic Tag object - representing a single dynamic tag entry from a + dynamic section. + + Allows dictionary-like access to the dynamic structure. For special + tags (those listed in the _HANDLED_TAGS set below), creates additional + attributes for convenience. For example, .soname will contain the actual + value of DT_SONAME (fetched from the dynamic symbol table). + """ + _HANDLED_TAGS = frozenset( + ['DT_NEEDED', 'DT_RPATH', 'DT_RUNPATH', 'DT_SONAME', + 'DT_SUNW_FILTER']) + + def __init__(self, entry, stringtable): + if stringtable is None: + raise ELFError('Creating DynamicTag without string table') + self.entry = entry + if entry.d_tag in self._HANDLED_TAGS: + setattr(self, entry.d_tag[3:].lower(), + stringtable.get_string(self.entry.d_val)) + + def __getitem__(self, name): + """ Implement dict-like access to entries + """ + return self.entry[name] + + def __repr__(self): + return '' % (self.entry.d_tag, self.entry) + + def __str__(self): + if self.entry.d_tag in self._HANDLED_TAGS: + s = '"%s"' % getattr(self, self.entry.d_tag[3:].lower()) + else: + s = '%#x' % self.entry.d_ptr + return '' % (self.entry.d_tag, s) + + +class Dynamic(object): + """ Shared functionality between dynamic sections and segments. + """ + def __init__(self, stream, elffile, stringtable, position): + self._stream = stream + self._elffile = elffile + self._elfstructs = elffile.structs + self._num_tags = -1 + self._offset = position + self._tagsize = self._elfstructs.Elf_Dyn.sizeof() + + # Do not access this directly yourself; use _get_stringtable() instead. + self._stringtable = stringtable + + def get_table_offset(self, tag_name): + """ Return the virtual address and file offset of a dynamic table. + """ + ptr = None + for tag in self._iter_tags(type=tag_name): + ptr = tag['d_ptr'] + break + + # If we found a virtual address, locate the offset in the file + # by using the program headers. + offset = None + if ptr: + offset = next(self._elffile.address_offsets(ptr), None) + + return ptr, offset + + def _get_stringtable(self): + """ Return a string table for looking up dynamic tag related strings. + + This won't be a "full" string table object, but will at least + support the get_string() function. + """ + if self._stringtable: + return self._stringtable + + # If the ELF has stripped its section table (which is unusual, but + # perfectly valid), we need to use the dynamic tags to locate the + # dynamic string table. + _, table_offset = self.get_table_offset('DT_STRTAB') + if table_offset is not None: + self._stringtable = _DynamicStringTable(self._stream, table_offset) + return self._stringtable + + # That didn't work for some reason. Let's use the section header + # even though this ELF is super weird. + self._stringtable = self._elffile.get_section_by_name(b'.dynstr') + return self._stringtable + + def _iter_tags(self, type=None): + """ Yield all raw tags (limit to |type| if specified) + """ + for n in itertools.count(): + tag = self._get_tag(n) + if type is None or tag['d_tag'] == type: + yield tag + if tag['d_tag'] == 'DT_NULL': + break + + def iter_tags(self, type=None): + """ Yield all tags (limit to |type| if specified) + """ + for tag in self._iter_tags(type=type): + yield DynamicTag(tag, self._get_stringtable()) + + def _get_tag(self, n): + """ Get the raw tag at index #n from the file + """ + offset = self._offset + n * self._tagsize + return struct_parse( + self._elfstructs.Elf_Dyn, + self._stream, + stream_pos=offset) + + def get_tag(self, n): + """ Get the tag at index #n from the file (DynamicTag object) + """ + return DynamicTag(self._get_tag(n), self._get_stringtable()) + + def num_tags(self): + """ Number of dynamic tags in the file + """ + if self._num_tags != -1: + return self._num_tags + + for n in itertools.count(): + tag = self.get_tag(n) + if tag.entry.d_tag == 'DT_NULL': + self._num_tags = n + 1 + return self._num_tags + + +class DynamicSection(Section, Dynamic): + """ ELF dynamic table section. Knows how to process the list of tags. + """ + def __init__(self, header, name, stream, elffile): + Section.__init__(self, header, name, stream) + stringtable = elffile.get_section(header['sh_link']) + Dynamic.__init__(self, stream, elffile, stringtable, self['sh_offset']) + + +class DynamicSegment(Segment, Dynamic): + """ ELF dynamic table segment. Knows how to process the list of tags. + """ + def __init__(self, header, stream, elffile): + # The string table section to be used to resolve string names in + # the dynamic tag array is the one pointed at by the sh_link field + # of the dynamic section header. + # So we must look for the dynamic section contained in the dynamic + # segment, we do so by searching for the dynamic section whose content + # is located at the same offset as the dynamic segment + stringtable = None + for section in elffile.iter_sections(): + if (isinstance(section, DynamicSection) and + section['sh_offset'] == header['p_offset']): + stringtable = elffile.get_section(section['sh_link']) + break + Segment.__init__(self, header, stream) + Dynamic.__init__(self, stream, elffile, stringtable, self['p_offset']) + + def iter_symbols(self): + """ Yield all symbols in this dynamic segment. The symbols are usually + the same as returned by SymbolTableSection.iter_symbols. However, + in stripped binaries, SymbolTableSection might have been removed. + This method reads from the mandatory dynamic tag DT_SYMTAB. + """ + tab_ptr, tab_offset = self.get_table_offset('DT_SYMTAB') + if tab_ptr is None or tab_offset is None: + raise ELFError('Segment does not contain DT_SYMTAB.') + + symbol_size = self._elfstructs.Elf_Sym.sizeof() + + # Find closest higher pointer than tab_ptr. We'll use that to mark the + # end of the symbol table. + nearest_ptr = None + for tag in self.iter_tags(): + tag_ptr = tag['d_ptr'] + if tag['d_tag'] == 'DT_SYMENT': + if symbol_size != tag['d_val']: + # DT_SYMENT is the size of one symbol entry. It must be the + # same as returned by Elf_Sym.sizeof. + raise ELFError('DT_SYMENT (%d) != Elf_Sym (%d).' % + (tag['d_val'], symbol_size)) + if (tag_ptr > tab_ptr and + (nearest_ptr is None or nearest_ptr > tag_ptr)): + nearest_ptr = tag_ptr + + if nearest_ptr is None: + # Use the end of segment that contains DT_SYMTAB. + for segment in self._elffile.iter_segments(): + if (segment['p_vaddr'] <= tab_ptr and + tab_ptr <= (segment['p_vaddr'] + segment['p_filesz'])): + nearest_ptr = segment['p_vaddr'] + segment['p_filesz'] + + if nearest_ptr is None: + raise ELFError('Cannot determine the end of DT_SYMTAB.') + + string_table = self._get_stringtable() + for i in range((nearest_ptr - tab_ptr) // symbol_size): + symbol = struct_parse(self._elfstructs.Elf_Sym, self._stream, + i * symbol_size + tab_offset) + symbol_name = string_table.get_string(symbol['st_name']) + yield Symbol(symbol, symbol_name) diff --git a/tools/utils/contrib/elftools/elf/elffile.py b/tools/utils/contrib/elftools/elf/elffile.py new file mode 100755 index 0000000000..cbb1428bde --- /dev/null +++ b/tools/utils/contrib/elftools/elf/elffile.py @@ -0,0 +1,378 @@ +#------------------------------------------------------------------------------- +# elftools: elf/elffile.py +# +# ELFFile - main class for accessing ELF files +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +from ..common.py3compat import BytesIO +from ..common.exceptions import ELFError +from ..common.utils import struct_parse, elf_assert +from ..construct import ConstructError +from .structs import ELFStructs +from .sections import ( + Section, StringTableSection, SymbolTableSection, + SUNWSyminfoTableSection, NullSection) +from .dynamic import DynamicSection, DynamicSegment +from .relocation import RelocationSection, RelocationHandler +from .gnuversions import ( + GNUVerNeedSection, GNUVerDefSection, + GNUVerSymSection) +from .segments import Segment, InterpSegment, NoteSegment +from ..dwarf.dwarfinfo import DWARFInfo, DebugSectionDescriptor, DwarfConfig + + +class ELFFile(object): + """ Creation: the constructor accepts a stream (file-like object) with the + contents of an ELF file. + + Accessible attributes: + + stream: + The stream holding the data of the file - must be a binary + stream (bytes, not string). + + elfclass: + 32 or 64 - specifies the word size of the target machine + + little_endian: + boolean - specifies the target machine's endianness + + header: + the complete ELF file header + + e_ident_raw: + the raw e_ident field of the header + """ + def __init__(self, stream): + self.stream = stream + self._identify_file() + self.structs = ELFStructs( + little_endian=self.little_endian, + elfclass=self.elfclass) + self.header = self._parse_elf_header() + + self.stream.seek(0) + self.e_ident_raw = self.stream.read(16) + + self._file_stringtable_section = self._get_file_stringtable() + self._section_name_map = None + + def num_sections(self): + """ Number of sections in the file + """ + return self['e_shnum'] + + def get_section(self, n): + """ Get the section at index #n from the file (Section object or a + subclass) + """ + section_header = self._get_section_header(n) + return self._make_section(section_header) + + def get_section_by_name(self, name): + """ Get a section from the file, by name. Return None if no such + section exists. + """ + # The first time this method is called, construct a name to number + # mapping + # + if self._section_name_map is None: + self._section_name_map = {} + for i, sec in enumerate(self.iter_sections()): + self._section_name_map[sec.name] = i + secnum = self._section_name_map.get(name, None) + return None if secnum is None else self.get_section(secnum) + + def iter_sections(self): + """ Yield all the sections in the file + """ + for i in range(self.num_sections()): + yield self.get_section(i) + + def num_segments(self): + """ Number of segments in the file + """ + return self['e_phnum'] + + def get_segment(self, n): + """ Get the segment at index #n from the file (Segment object) + """ + segment_header = self._get_segment_header(n) + return self._make_segment(segment_header) + + def iter_segments(self): + """ Yield all the segments in the file + """ + for i in range(self.num_segments()): + yield self.get_segment(i) + + def address_offsets(self, start, size=1): + """ Yield a file offset for each ELF segment containing a memory region. + + A memory region is defined by the range [start...start+size). The + offset of the region is yielded. + """ + end = start + size + for seg in self.iter_segments(): + if (start >= seg['p_vaddr'] and + end <= seg['p_vaddr'] + seg['p_filesz']): + yield start - seg['p_vaddr'] + seg['p_offset'] + + def has_dwarf_info(self): + """ Check whether this file appears to have debugging information. + We assume that if it has the debug_info section, it has all theother + required sections as well. + """ + return bool(self.get_section_by_name(b'.debug_info')) + + def get_dwarf_info(self, relocate_dwarf_sections=True): + """ Return a DWARFInfo object representing the debugging information in + this file. + + If relocate_dwarf_sections is True, relocations for DWARF sections + are looked up and applied. + """ + # Expect that has_dwarf_info was called, so at least .debug_info is + # present. + # Sections that aren't found will be passed as None to DWARFInfo. + # + debug_sections = {} + for secname in (b'.debug_info', b'.debug_abbrev', b'.debug_str', + b'.debug_line', b'.debug_frame', + b'.debug_loc', b'.debug_ranges'): + section = self.get_section_by_name(secname) + if section is None: + debug_sections[secname] = None + else: + debug_sections[secname] = self._read_dwarf_section( + section, + relocate_dwarf_sections) + + return DWARFInfo( + config=DwarfConfig( + little_endian=self.little_endian, + default_address_size=self.elfclass // 8, + machine_arch=self.get_machine_arch()), + debug_info_sec=debug_sections[b'.debug_info'], + debug_abbrev_sec=debug_sections[b'.debug_abbrev'], + debug_frame_sec=debug_sections[b'.debug_frame'], + # TODO(eliben): reading of eh_frame is not hooked up yet + eh_frame_sec=None, + debug_str_sec=debug_sections[b'.debug_str'], + debug_loc_sec=debug_sections[b'.debug_loc'], + debug_ranges_sec=debug_sections[b'.debug_ranges'], + debug_line_sec=debug_sections[b'.debug_line']) + + def get_machine_arch(self): + """ Return the machine architecture, as detected from the ELF header. + Not all architectures are supported at the moment. + """ + if self['e_machine'] == 'EM_X86_64': + return 'x64' + elif self['e_machine'] in ('EM_386', 'EM_486'): + return 'x86' + elif self['e_machine'] == 'EM_ARM': + return 'ARM' + elif self['e_machine'] == 'EM_AARCH64': + return 'AArch64' + elif self['e_machine'] == 'EM_MIPS': + return 'MIPS' + else: + return '' + + #-------------------------------- PRIVATE --------------------------------# + + def __getitem__(self, name): + """ Implement dict-like access to header entries + """ + return self.header[name] + + def _identify_file(self): + """ Verify the ELF file and identify its class and endianness. + """ + # Note: this code reads the stream directly, without using ELFStructs, + # since we don't yet know its exact format. ELF was designed to be + # read like this - its e_ident field is word-size and endian agnostic. + # + self.stream.seek(0) + magic = self.stream.read(4) + elf_assert(magic == b'\x7fELF', 'Magic number does not match') + + ei_class = self.stream.read(1) + if ei_class == b'\x01': + self.elfclass = 32 + elif ei_class == b'\x02': + self.elfclass = 64 + else: + raise ELFError('Invalid EI_CLASS %s' % repr(ei_class)) + + ei_data = self.stream.read(1) + if ei_data == b'\x01': + self.little_endian = True + elif ei_data == b'\x02': + self.little_endian = False + else: + raise ELFError('Invalid EI_DATA %s' % repr(ei_data)) + + def _section_offset(self, n): + """ Compute the offset of section #n in the file + """ + return self['e_shoff'] + n * self['e_shentsize'] + + def _segment_offset(self, n): + """ Compute the offset of segment #n in the file + """ + return self['e_phoff'] + n * self['e_phentsize'] + + def _make_segment(self, segment_header): + """ Create a Segment object of the appropriate type + """ + segtype = segment_header['p_type'] + if segtype == 'PT_INTERP': + return InterpSegment(segment_header, self.stream) + elif segtype == 'PT_DYNAMIC': + return DynamicSegment(segment_header, self.stream, self) + elif segtype == 'PT_NOTE': + return NoteSegment(segment_header, self.stream, self) + else: + return Segment(segment_header, self.stream) + + def _get_section_header(self, n): + """ Find the header of section #n, parse it and return the struct + """ + return struct_parse( + self.structs.Elf_Shdr, + self.stream, + stream_pos=self._section_offset(n)) + + def _get_section_name(self, section_header): + """ Given a section header, find this section's name in the file's + string table + """ + name_offset = section_header['sh_name'] + return self._file_stringtable_section.get_string(name_offset) + + def _make_section(self, section_header): + """ Create a section object of the appropriate type + """ + name = self._get_section_name(section_header) + sectype = section_header['sh_type'] + + if sectype == 'SHT_STRTAB': + return StringTableSection(section_header, name, self.stream) + elif sectype == 'SHT_NULL': + return NullSection(section_header, name, self.stream) + elif sectype in ('SHT_SYMTAB', 'SHT_DYNSYM', 'SHT_SUNW_LDYNSYM'): + return self._make_symbol_table_section(section_header, name) + elif sectype == 'SHT_SUNW_syminfo': + return self._make_sunwsyminfo_table_section(section_header, name) + elif sectype == 'SHT_GNU_verneed': + return self._make_gnu_verneed_section(section_header, name) + elif sectype == 'SHT_GNU_verdef': + return self._make_gnu_verdef_section(section_header, name) + elif sectype == 'SHT_GNU_versym': + return self._make_gnu_versym_section(section_header, name) + elif sectype in ('SHT_REL', 'SHT_RELA'): + return RelocationSection( + section_header, name, self.stream, self) + elif sectype == 'SHT_DYNAMIC': + return DynamicSection(section_header, name, self.stream, self) + else: + return Section(section_header, name, self.stream) + + def _make_symbol_table_section(self, section_header, name): + """ Create a SymbolTableSection + """ + linked_strtab_index = section_header['sh_link'] + strtab_section = self.get_section(linked_strtab_index) + return SymbolTableSection( + section_header, name, self.stream, + elffile=self, + stringtable=strtab_section) + + def _make_sunwsyminfo_table_section(self, section_header, name): + """ Create a SUNWSyminfoTableSection + """ + linked_strtab_index = section_header['sh_link'] + strtab_section = self.get_section(linked_strtab_index) + return SUNWSyminfoTableSection( + section_header, name, self.stream, + elffile=self, + symboltable=strtab_section) + + def _make_gnu_verneed_section(self, section_header, name): + """ Create a GNUVerNeedSection + """ + linked_strtab_index = section_header['sh_link'] + strtab_section = self.get_section(linked_strtab_index) + return GNUVerNeedSection( + section_header, name, self.stream, + elffile=self, + stringtable=strtab_section) + + def _make_gnu_verdef_section(self, section_header, name): + """ Create a GNUVerDefSection + """ + linked_strtab_index = section_header['sh_link'] + strtab_section = self.get_section(linked_strtab_index) + return GNUVerDefSection( + section_header, name, self.stream, + elffile=self, + stringtable=strtab_section) + + def _make_gnu_versym_section(self, section_header, name): + """ Create a GNUVerSymSection + """ + linked_strtab_index = section_header['sh_link'] + strtab_section = self.get_section(linked_strtab_index) + return GNUVerSymSection( + section_header, name, self.stream, + elffile=self, + symboltable=strtab_section) + + def _get_segment_header(self, n): + """ Find the header of segment #n, parse it and return the struct + """ + return struct_parse( + self.structs.Elf_Phdr, + self.stream, + stream_pos=self._segment_offset(n)) + + def _get_file_stringtable(self): + """ Find the file's string table section + """ + stringtable_section_num = self['e_shstrndx'] + return StringTableSection( + header=self._get_section_header(stringtable_section_num), + name='', + stream=self.stream) + + def _parse_elf_header(self): + """ Parses the ELF file header and assigns the result to attributes + of this object. + """ + return struct_parse(self.structs.Elf_Ehdr, self.stream, stream_pos=0) + + def _read_dwarf_section(self, section, relocate_dwarf_sections): + """ Read the contents of a DWARF section from the stream and return a + DebugSectionDescriptor. Apply relocations if asked to. + """ + self.stream.seek(section['sh_offset']) + # The section data is read into a new stream, for processing + section_stream = BytesIO() + section_stream.write(self.stream.read(section['sh_size'])) + + if relocate_dwarf_sections: + reloc_handler = RelocationHandler(self) + reloc_section = reloc_handler.find_relocations_for_section(section) + if reloc_section is not None: + reloc_handler.apply_section_relocations( + section_stream, reloc_section) + + return DebugSectionDescriptor( + stream=section_stream, + name=section.name, + global_offset=section['sh_offset'], + size=section['sh_size']) diff --git a/tools/utils/contrib/elftools/elf/enums.py b/tools/utils/contrib/elftools/elf/enums.py new file mode 100755 index 0000000000..494827f789 --- /dev/null +++ b/tools/utils/contrib/elftools/elf/enums.py @@ -0,0 +1,844 @@ +#------------------------------------------------------------------------------- +# elftools: elf/enums.py +# +# Mappings of enum names to values +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +from ..construct import Pass + + +# e_ident[EI_CLASS] in the ELF header +ENUM_EI_CLASS = dict( + ELFCLASSNONE=0, + ELFCLASS32=1, + ELFCLASS64=2 +) + +# e_ident[EI_DATA] in the ELF header +ENUM_EI_DATA = dict( + ELFDATANONE=0, + ELFDATA2LSB=1, + ELFDATA2MSB=2 +) + +# e_version in the ELF header +ENUM_E_VERSION = dict( + EV_NONE=0, + EV_CURRENT=1, + _default_=Pass, +) + +# e_ident[EI_OSABI] in the ELF header +ENUM_EI_OSABI = dict( + ELFOSABI_SYSV=0, + ELFOSABI_HPUX=1, + ELFOSABI_NETBSD=2, + ELFOSABI_LINUX=3, + ELFOSABI_HURD=4, + ELFOSABI_SOLARIS=6, + ELFOSABI_AIX=7, + ELFOSABI_IRIX=8, + ELFOSABI_FREEBSD=9, + ELFOSABI_TRU64=10, + ELFOSABI_MODESTO=11, + ELFOSABI_OPENBSD=12, + ELFOSABI_OPENVMS=13, + ELFOSABI_NSK=14, + ELFOSABI_AROS=15, + ELFOSABI_ARM_AEABI=64, + ELFOSABI_ARM=97, + ELFOSABI_STANDALONE=255, + _default_=Pass, +) + +# e_type in the ELF header +ENUM_E_TYPE = dict( + ET_NONE=0, + ET_REL=1, + ET_EXEC=2, + ET_DYN=3, + ET_CORE=4, + ET_LOPROC=0xff00, + ET_HIPROC=0xffff, + _default_=Pass, +) + +# e_machine in the ELF header +ENUM_E_MACHINE = dict( + EM_NONE=0, + EM_M32=1, + EM_SPARC=2, + EM_386=3, + EM_68K=4, + EM_88K=5, + EM_860=7, + EM_MIPS=8, + EM_S370=9, + EM_MIPS_RS3_LE=10, + EM_PARISC=15, + EM_VPP500=17, + EM_SPARC32PLUS=18, + EM_960=19, + EM_PPC=20, + EM_PPC64=21, + EM_S390=22, + EM_V800=36, + EM_FR20=37, + EM_RH32=38, + EM_RCE=39, + EM_ARM=40, + EM_ALPHA=41, + EM_SH=42, + EM_SPARCV9=43, + EM_TRICORE=44, + EM_ARC=45, + EM_H8_300=46, + EM_H8_300H=47, + EM_H8S=48, + EM_H8_500=49, + EM_IA_64=50, + EM_MIPS_X=51, + EM_COLDFIRE=52, + EM_68HC12=53, + EM_MMA=54, + EM_PCP=55, + EM_NCPU=56, + EM_NDR1=57, + EM_STARCORE=58, + EM_ME16=59, + EM_ST100=60, + EM_TINYJ=61, + EM_X86_64=62, + EM_PDSP=63, + EM_PDP10=64, + EM_PDP11=65, + EM_FX66=66, + EM_ST9PLUS=67, + EM_ST7=68, + EM_68HC16=69, + EM_68HC11=70, + EM_68HC08=71, + EM_68HC05=72, + EM_SVX=73, + EM_ST19=74, + EM_VAX=75, + EM_CRIS=76, + EM_JAVELIN=77, + EM_FIREPATH=78, + EM_ZSP=79, + EM_MMIX=80, + EM_HUANY=81, + EM_PRISM=82, + EM_AVR=83, + EM_FR30=84, + EM_D10V=85, + EM_D30V=86, + EM_V850=87, + EM_M32R=88, + EM_MN10300=89, + EM_MN10200=90, + EM_PJ=91, + EM_OPENRISC=92, + EM_ARC_A5=93, + EM_XTENSA=94, + EM_VIDEOCORE=95, + EM_TMM_GPP=96, + EM_NS32K=97, + EM_TPC=98, + EM_SNP1K=99, + EM_ST200=100, + EM_IP2K=101, + EM_MAX=102, + EM_CR=103, + EM_F2MC16=104, + EM_MSP430=105, + EM_BLACKFIN=106, + EM_SE_C33=107, + EM_SEP=108, + EM_ARCA=109, + EM_UNICORE=110, + EM_L10M=180, + EM_AARCH64=183, + _default_=Pass, +) + +# sh_type in the section header +ENUM_SH_TYPE = dict( + SHT_NULL=0, + SHT_PROGBITS=1, + SHT_SYMTAB=2, + SHT_STRTAB=3, + SHT_RELA=4, + SHT_HASH=5, + SHT_DYNAMIC=6, + SHT_NOTE=7, + SHT_NOBITS=8, + SHT_REL=9, + SHT_SHLIB=10, + SHT_DYNSYM=11, + SHT_INIT_ARRAY=14, + SHT_FINI_ARRAY=15, + SHT_PREINIT_ARRAY=16, + SHT_GROUP=17, + SHT_SYMTAB_SHNDX=18, + SHT_NUM=19, + SHT_LOOS=0x60000000, + SHT_GNU_HASH=0x6ffffff6, + SHT_GNU_verdef=0x6ffffffd, # also SHT_SUNW_verdef + SHT_GNU_verneed=0x6ffffffe, # also SHT_SUNW_verneed + SHT_GNU_versym=0x6fffffff, # also SHT_SUNW_versym, SHT_HIOS + SHT_LOPROC=0x70000000, + SHT_HIPROC=0x7fffffff, + SHT_LOUSER=0x80000000, + SHT_HIUSER=0xffffffff, + SHT_AMD64_UNWIND=0x70000001, + SHT_SUNW_LDYNSYM=0x6ffffff3, + SHT_SUNW_syminfo=0x6ffffffc, + SHT_ARM_EXIDX=0x70000001, # also SHT_MIPS_MSYM + SHT_ARM_PREEMPTMAP=0x70000002, # also SHT_MIPS_CONFLICT + SHT_ARM_ATTRIBUTES=0x70000003, # also SHT_MIPS_GPTAB + SHT_ARM_DEBUGOVERLAY=0x70000004, # also SHT_MIPS_UCODE + SHT_MIPS_LIBLIST=0x70000000, + SHT_MIPS_DEBUG=0x70000005, + SHT_MIPS_REGINFO=0x70000006, + SHT_MIPS_PACKAGE=0x70000007, + SHT_MIPS_PACKSYM=0x70000008, + SHT_MIPS_RELD=0x70000009, + SHT_MIPS_IFACE=0x7000000b, + SHT_MIPS_CONTENT=0x7000000c, + SHT_MIPS_OPTIONS=0x7000000d, + SHT_MIPS_SHDR=0x70000010, + SHT_MIPS_FDESC=0x70000011, + SHT_MIPS_EXTSYM=0x70000012, + SHT_MIPS_DENSE=0x70000013, + SHT_MIPS_PDESC=0x70000014, + SHT_MIPS_LOCSYM=0x70000015, + SHT_MIPS_AUXSYM=0x70000016, + SHT_MIPS_OPTSYM=0x70000017, + SHT_MIPS_LOCSTR=0x70000018, + SHT_MIPS_LINE=0x70000019, + SHT_MIPS_RFDESC=0x7000001a, + SHT_MIPS_DELTASYM=0x7000001b, + SHT_MIPS_DELTAINST=0x7000001c, + SHT_MIPS_DELTACLASS=0x7000001d, + SHT_MIPS_DWARF=0x7000001e, + SHT_MIPS_DELTADECL=0x7000001f, + SHT_MIPS_SYMBOL_LIB=0x70000020, + SHT_MIPS_EVENTS=0x70000021, + SHT_MIPS_TRANSLATE=0x70000022, + SHT_MIPS_PIXIE=0x70000023, + SHT_MIPS_XLATE=0x70000024, + SHT_MIPS_XLATE_DEBUG=0x70000025, + SHT_MIPS_WHIRL=0x70000026, + SHT_MIPS_EH_REGION=0x70000027, + SHT_MIPS_XLATE_OLD=0x70000028, + SHT_MIPS_PDR_EXCEPTION=0x70000029, + _default_=Pass, +) + +# p_type in the program header +# some values scavenged from the ELF headers in binutils-2.21 +ENUM_P_TYPE = dict( + PT_NULL=0, + PT_LOAD=1, + PT_DYNAMIC=2, + PT_INTERP=3, + PT_NOTE=4, + PT_SHLIB=5, + PT_PHDR=6, + PT_TLS=7, + PT_LOOS=0x60000000, + PT_HIOS=0x6fffffff, + PT_LOPROC=0x70000000, + PT_HIPROC=0x7fffffff, + PT_GNU_EH_FRAME=0x6474e550, + PT_GNU_STACK=0x6474e551, + PT_GNU_RELRO=0x6474e552, + PT_ARM_ARCHEXT=0x70000000, + PT_ARM_EXIDX=0x70000001, + PT_ARM_UNWIND=0x70000001, + PT_AARCH64_ARCHEXT=0x70000000, + PT_AARCH64_UNWIND=0x70000001, + _default_=Pass, +) + +# st_info bindings in the symbol header +ENUM_ST_INFO_BIND = dict( + STB_LOCAL=0, + STB_GLOBAL=1, + STB_WEAK=2, + STB_NUM=3, + STB_LOOS=10, + STB_HIOS=12, + STB_LOPROC=13, + STB_HIPROC=15, + _default_=Pass, +) + +# st_info type in the symbol header +ENUM_ST_INFO_TYPE = dict( + STT_NOTYPE=0, + STT_OBJECT=1, + STT_FUNC=2, + STT_SECTION=3, + STT_FILE=4, + STT_COMMON=5, + STT_TLS=6, + STT_NUM=7, + STT_RELC=8, + STT_SRELC=9, + STT_LOOS=10, + STT_HIOS=12, + STT_LOPROC=13, + STT_HIPROC=15, + _default_=Pass, +) + +# visibility from st_other +ENUM_ST_VISIBILITY = dict( + STV_DEFAULT=0, + STV_INTERNAL=1, + STV_HIDDEN=2, + STV_PROTECTED=3, + STV_EXPORTED=4, + STV_SINGLETON=5, + STV_ELIMINATE=6, + _default_=Pass, +) + +# st_shndx +ENUM_ST_SHNDX = dict( + SHN_UNDEF=0, + SHN_ABS=0xfff1, + SHN_COMMON=0xfff2, + _default_=Pass, +) + +# d_tag +ENUM_D_TAG = dict( + DT_NULL=0, + DT_NEEDED=1, + DT_PLTRELSZ=2, + DT_PLTGOT=3, + DT_HASH=4, + DT_STRTAB=5, + DT_SYMTAB=6, + DT_RELA=7, + DT_RELASZ=8, + DT_RELAENT=9, + DT_STRSZ=10, + DT_SYMENT=11, + DT_INIT=12, + DT_FINI=13, + DT_SONAME=14, + DT_RPATH=15, + DT_SYMBOLIC=16, + DT_REL=17, + DT_RELSZ=18, + DT_RELENT=19, + DT_PLTREL=20, + DT_DEBUG=21, + DT_TEXTREL=22, + DT_JMPREL=23, + DT_BIND_NOW=24, + DT_INIT_ARRAY=25, + DT_FINI_ARRAY=26, + DT_INIT_ARRAYSZ=27, + DT_FINI_ARRAYSZ=28, + DT_RUNPATH=29, + DT_FLAGS=30, + DT_ENCODING=32, + DT_PREINIT_ARRAY=32, + DT_PREINIT_ARRAYSZ=33, + DT_NUM=34, + DT_LOOS=0x6000000d, + DT_SUNW_AUXILIARY=0x6000000d, + DT_SUNW_RTLDINF=0x6000000e, + DT_SUNW_FILTER=0x6000000f, + DT_SUNW_CAP=0x60000010, + DT_SUNW_SYMTAB=0x60000011, + DT_SUNW_SYMSZ=0x60000012, + DT_SUNW_ENCODING=0x60000013, + DT_SUNW_SORTENT=0x60000013, + DT_SUNW_SYMSORT=0x60000014, + DT_SUNW_SYMSORTSZ=0x60000015, + DT_SUNW_TLSSORT=0x60000016, + DT_SUNW_TLSSORTSZ=0x60000017, + DT_SUNW_CAPINFO=0x60000018, + DT_SUNW_STRPAD=0x60000019, + DT_SUNW_CAPCHAIN=0x6000001a, + DT_SUNW_LDMACH=0x6000001b, + DT_SUNW_CAPCHAINENT=0x6000001d, + DT_SUNW_CAPCHAINSZ=0x6000001f, + DT_HIOS=0x6ffff000, + DT_LOPROC=0x70000000, + DT_HIPROC=0x7fffffff, + DT_PROCNUM=0x35, + DT_VALRNGLO=0x6ffffd00, + DT_GNU_PRELINKED=0x6ffffdf5, + DT_GNU_CONFLICTSZ=0x6ffffdf6, + DT_GNU_LIBLISTSZ=0x6ffffdf7, + DT_CHECKSUM=0x6ffffdf8, + DT_PLTPADSZ=0x6ffffdf9, + DT_MOVEENT=0x6ffffdfa, + DT_MOVESZ=0x6ffffdfb, + DT_SYMINSZ=0x6ffffdfe, + DT_SYMINENT=0x6ffffdff, + DT_GNU_HASH=0x6ffffef5, + DT_TLSDESC_PLT=0x6ffffef6, + DT_TLSDESC_GOT=0x6ffffef7, + DT_GNU_CONFLICT=0x6ffffef8, + DT_GNU_LIBLIST=0x6ffffef9, + DT_CONFIG=0x6ffffefa, + DT_DEPAUDIT=0x6ffffefb, + DT_AUDIT=0x6ffffefc, + DT_PLTPAD=0x6ffffefd, + DT_MOVETAB=0x6ffffefe, + DT_SYMINFO=0x6ffffeff, + DT_VERSYM=0x6ffffff0, + DT_RELACOUNT=0x6ffffff9, + DT_RELCOUNT=0x6ffffffa, + DT_FLAGS_1=0x6ffffffb, + DT_VERDEF=0x6ffffffc, + DT_VERDEFNUM=0x6ffffffd, + DT_VERNEED=0x6ffffffe, + DT_VERNEEDNUM=0x6fffffff, + DT_AUXILIARY=0x7ffffffd, + DT_FILTER=0x7fffffff, + _default_=Pass, +) + +ENUM_RELOC_TYPE_MIPS = dict( + R_MIPS_NONE=0, + R_MIPS_16=1, + R_MIPS_32=2, + R_MIPS_REL32=3, + R_MIPS_26=4, + R_MIPS_HI16=5, + R_MIPS_LO16=6, + R_MIPS_GPREL16=7, + R_MIPS_LITERAL=8, + R_MIPS_GOT16=9, + R_MIPS_PC16=10, + R_MIPS_CALL16=11, + R_MIPS_GPREL32=12, + R_MIPS_SHIFT5=16, + R_MIPS_SHIFT6=17, + R_MIPS_64=18, + R_MIPS_GOT_DISP=19, + R_MIPS_GOT_PAGE=20, + R_MIPS_GOT_OFST=21, + R_MIPS_GOT_HI16=22, + R_MIPS_GOT_LO16=23, + R_MIPS_SUB=24, + R_MIPS_INSERT_A=25, + R_MIPS_INSERT_B=26, + R_MIPS_DELETE=27, + R_MIPS_HIGHER=28, + R_MIPS_HIGHEST=29, + R_MIPS_CALL_HI16=30, + R_MIPS_CALL_LO16=31, + R_MIPS_SCN_DISP=32, + R_MIPS_REL16=33, + R_MIPS_ADD_IMMEDIATE=34, + R_MIPS_PJUMP=35, + R_MIPS_RELGOT=36, + R_MIPS_JALR=37, + R_MIPS_TLS_DTPMOD32=38, + R_MIPS_TLS_DTPREL32=39, + R_MIPS_TLS_DTPMOD64=40, + R_MIPS_TLS_DTPREL64=41, + R_MIPS_TLS_GD=42, + R_MIPS_TLS_LDM=43, + R_MIPS_TLS_DTPREL_HI16=44, + R_MIPS_TLS_DTPREL_LO16=45, + R_MIPS_TLS_GOTTPREL=46, + R_MIPS_TLS_TPREL32=47, + R_MIPS_TLS_TPREL64=48, + R_MIPS_TLS_TPREL_HI16=49, + R_MIPS_TLS_TPREL_LO16=50, + R_MIPS_GLOB_DAT=51, + R_MIPS_COPY=126, + R_MIPS_JUMP_SLOT=127, + _default_=Pass, +) + +ENUM_RELOC_TYPE_i386 = dict( + R_386_NONE=0, + R_386_32=1, + R_386_PC32=2, + R_386_GOT32=3, + R_386_PLT32=4, + R_386_COPY=5, + R_386_GLOB_DAT=6, + R_386_JUMP_SLOT=7, + R_386_RELATIVE=8, + R_386_GOTOFF=9, + R_386_GOTPC=10, + R_386_32PLT=11, + R_386_TLS_TPOFF=14, + R_386_TLS_IE=15, + R_386_TLS_GOTIE=16, + R_386_TLS_LE=17, + R_386_TLS_GD=18, + R_386_TLS_LDM=19, + R_386_16=20, + R_386_PC16=21, + R_386_8=22, + R_386_PC8=23, + R_386_TLS_GD_32=24, + R_386_TLS_GD_PUSH=25, + R_386_TLS_GD_CALL=26, + R_386_TLS_GD_POP=27, + R_386_TLS_LDM_32=28, + R_386_TLS_LDM_PUSH=29, + R_386_TLS_LDM_CALL=30, + R_386_TLS_LDM_POP=31, + R_386_TLS_LDO_32=32, + R_386_TLS_IE_32=33, + R_386_TLS_LE_32=34, + R_386_TLS_DTPMOD32=35, + R_386_TLS_DTPOFF32=36, + R_386_TLS_TPOFF32=37, + R_386_TLS_GOTDESC=39, + R_386_TLS_DESC_CALL=40, + R_386_TLS_DESC=41, + R_386_IRELATIVE=42, + R_386_USED_BY_INTEL_200=200, + R_386_GNU_VTINHERIT=250, + R_386_GNU_VTENTRY=251, + _default_=Pass, +) + +ENUM_RELOC_TYPE_x64 = dict( + R_X86_64_NONE=0, + R_X86_64_64=1, + R_X86_64_PC32=2, + R_X86_64_GOT32=3, + R_X86_64_PLT32=4, + R_X86_64_COPY=5, + R_X86_64_GLOB_DAT=6, + R_X86_64_JUMP_SLOT=7, + R_X86_64_RELATIVE=8, + R_X86_64_GOTPCREL=9, + R_X86_64_32=10, + R_X86_64_32S=11, + R_X86_64_16=12, + R_X86_64_PC16=13, + R_X86_64_8=14, + R_X86_64_PC8=15, + R_X86_64_DTPMOD64=16, + R_X86_64_DTPOFF64=17, + R_X86_64_TPOFF64=18, + R_X86_64_TLSGD=19, + R_X86_64_TLSLD=20, + R_X86_64_DTPOFF32=21, + R_X86_64_GOTTPOFF=22, + R_X86_64_TPOFF32=23, + R_X86_64_PC64=24, + R_X86_64_GOTOFF64=25, + R_X86_64_GOTPC32=26, + R_X86_64_GOT64=27, + R_X86_64_GOTPCREL64=28, + R_X86_64_GOTPC64=29, + R_X86_64_GOTPLT64=30, + R_X86_64_PLTOFF64=31, + R_X86_64_GOTPC32_TLSDESC=34, + R_X86_64_TLSDESC_CALL=35, + R_X86_64_TLSDESC=36, + R_X86_64_IRELATIVE=37, + R_X86_64_GNU_VTINHERIT=250, + R_X86_64_GNU_VTENTRY=251, + _default_=Pass, +) + +# Sunw Syminfo Bound To special values +ENUM_SUNW_SYMINFO_BOUNDTO = dict( + SYMINFO_BT_SELF=0xffff, + SYMINFO_BT_PARENT=0xfffe, + SYMINFO_BT_NONE=0xfffd, + SYMINFO_BT_EXTERN=0xfffc, + _default_=Pass, +) + +# Versym section, version dependency index +ENUM_VERSYM = dict( + VER_NDX_LOCAL=0, + VER_NDX_GLOBAL=1, + VER_NDX_LORESERVE=0xff00, + VER_NDX_ELIMINATE=0xff01, + _default_=Pass, +) +# Sunw Syminfo Bound To special values +ENUM_SUNW_SYMINFO_BOUNDTO = dict( + SYMINFO_BT_SELF=0xffff, + SYMINFO_BT_PARENT=0xfffe, + SYMINFO_BT_NONE=0xfffd, + SYMINFO_BT_EXTERN=0xfffc, + _default_=Pass, +) + +# PT_NOTE section types +ENUM_NOTE_N_TYPE = dict( + NT_GNU_ABI_TAG=1, + NT_GNU_HWCAP=2, + NT_GNU_BUILD_ID=3, + NT_GNU_GOLD_VERSION=4, + _default_=Pass, +) + +# Values in GNU .note.ABI-tag notes (n_type=='NT_GNU_ABI_TAG') +ENUM_NOTE_ABI_TAG_OS = dict( + ELF_NOTE_OS_LINUX=0, + ELF_NOTE_OS_GNU=1, + ELF_NOTE_OS_SOLARIS2=2, + ELF_NOTE_OS_FREEBSD=3, + ELF_NOTE_OS_NETBSD=4, + ELF_NOTE_OS_SYLLABLE=5, + _default_=Pass, +) + +ENUM_RELOC_TYPE_ARM = dict( + R_ARM_NONE=0, + R_ARM_PC24=1, + R_ARM_ABS32=2, + R_ARM_REL32=3, + R_ARM_LDR_PC_G0=4, + R_ARM_ABS16=5, + R_ARM_ABS12=6, + R_ARM_THM_ABS5=7, + R_ARM_ABS8=8, + R_ARM_SBREL32=9, + R_ARM_THM_CALL=10, + R_ARM_THM_PC8=11, + R_ARM_BREL_ADJ=12, + R_ARM_SWI24=13, + R_ARM_THM_SWI8=14, + R_ARM_XPC25=15, + R_ARM_THM_XPC22=16, + R_ARM_TLS_DTPMOD32=17, + R_ARM_TLS_DTPOFF32=18, + R_ARM_TLS_TPOFF32=19, + R_ARM_COPY=20, + R_ARM_GLOB_DAT=21, + R_ARM_JUMP_SLOT=22, + R_ARM_RELATIVE=23, + R_ARM_GOTOFF32=24, + R_ARM_BASE_PREL=25, + R_ARM_GOT_BREL=26, + R_ARM_PLT32=27, + R_ARM_CALL=28, + R_ARM_JUMP24=29, + R_ARM_THM_JUMP24=30, + R_ARM_BASE_ABS=31, + R_ARM_ALU_PCREL_7_0=32, + R_ARM_ALU_PCREL_15_8=33, + R_ARM_ALU_PCREL_23_15=34, + R_ARM_LDR_SBREL_11_0_NC=35, + R_ARM_ALU_SBREL_19_12_NC=36, + R_ARM_ALU_SBREL_27_20_CK=37, + R_ARM_TARGET1=38, + R_ARM_SBREL31=39, + R_ARM_V4BX=40, + R_ARM_TARGET2=41, + R_ARM_PREL31=42, + R_ARM_MOVW_ABS_NC=43, + R_ARM_MOVT_ABS=44, + R_ARM_MOVW_PREL_NC=45, + R_ARM_MOVT_PREL=46, + R_ARM_THM_MOVW_ABS_NC=47, + R_ARM_THM_MOVT_ABS=48, + R_ARM_THM_MOVW_PREL_NC=49, + R_ARM_THM_MOVT_PREL=50, + R_ARM_THM_JUMP19=51, + R_ARM_THM_JUMP6=52, + R_ARM_THM_ALU_PREL_11_0=53, + R_ARM_THM_PC12=54, + R_ARM_ABS32_NOI=55, + R_ARM_REL32_NOI=56, + R_ARM_ALU_PC_G0_NC=57, + R_ARM_ALU_PC_G0=58, + R_ARM_ALU_PC_G1_NC=59, + R_ARM_ALU_PC_G1=60, + R_ARM_ALU_PC_G2=61, + R_ARM_LDR_PC_G1=62, + R_ARM_LDR_PC_G2=63, + R_ARM_LDRS_PC_G0=64, + R_ARM_LDRS_PC_G1=65, + R_ARM_LDRS_PC_G2=66, + R_ARM_LDC_PC_G0=67, + R_ARM_LDC_PC_G1=68, + R_ARM_LDC_PC_G2=69, + R_ARM_ALU_SB_G0_NC=70, + R_ARM_ALU_SB_G0=71, + R_ARM_ALU_SB_G1_NC=72, + R_ARM_ALU_SB_G1=73, + R_ARM_ALU_SB_G2=74, + R_ARM_LDR_SB_G0=75, + R_ARM_LDR_SB_G1=76, + R_ARM_LDR_SB_G2=77, + R_ARM_LDRS_SB_G0=78, + R_ARM_LDRS_SB_G1=79, + R_ARM_LDRS_SB_G2=80, + R_ARM_LDC_SB_G0=81, + R_ARM_LDC_SB_G1=82, + R_ARM_LDC_SB_G2=83, + R_ARM_MOVW_BREL_NC=84, + R_ARM_MOVT_BREL=85, + R_ARM_MOVW_BREL=86, + R_ARM_THM_MOVW_BREL_NC=87, + R_ARM_THM_MOVT_BREL=88, + R_ARM_THM_MOVW_BREL=89, + R_ARM_PLT32_ABS=94, + R_ARM_GOT_ABS=95, + R_ARM_GOT_PREL=96, + R_ARM_GOT_BREL12=97, + R_ARM_GOTOFF12=98, + R_ARM_GOTRELAX=99, + R_ARM_GNU_VTENTRY=100, + R_ARM_GNU_VTINHERIT=101, + R_ARM_THM_JUMP11=102, + R_ARM_THM_JUMP8=103, + R_ARM_TLS_GD32=104, + R_ARM_TLS_LDM32=105, + R_ARM_TLS_LDO32=106, + R_ARM_TLS_IE32=107, + R_ARM_TLS_LE32=108, + R_ARM_TLS_LDO12=109, + R_ARM_TLS_LE12=110, + R_ARM_TLS_IE12GP=111, + R_ARM_PRIVATE_0=112, + R_ARM_PRIVATE_1=113, + R_ARM_PRIVATE_2=114, + R_ARM_PRIVATE_3=115, + R_ARM_PRIVATE_4=116, + R_ARM_PRIVATE_5=117, + R_ARM_PRIVATE_6=118, + R_ARM_PRIVATE_7=119, + R_ARM_PRIVATE_8=120, + R_ARM_PRIVATE_9=121, + R_ARM_PRIVATE_10=122, + R_ARM_PRIVATE_11=123, + R_ARM_PRIVATE_12=124, + R_ARM_PRIVATE_13=125, + R_ARM_PRIVATE_14=126, + R_ARM_PRIVATE_15=127, + R_ARM_ME_TOO=128, + R_ARM_THM_TLS_DESCSEQ16=129, + R_ARM_THM_TLS_DESCSEQ32=130, + R_ARM_THM_GOT_BREL12=131, + R_ARM_IRELATIVE=140, +) + +ENUM_RELOC_TYPE_AARCH64 = dict( + R_AARCH64_NONE=256, + R_AARCH64_ABS64=257, + R_AARCH64_ABS32=258, + R_AARCH64_ABS16=259, + R_AARCH64_PREL64=260, + R_AARCH64_PREL32=261, + R_AARCH64_PREL16=262, + R_AARCH64_MOVW_UABS_G0=263, + R_AARCH64_MOVW_UABS_G0_NC=264, + R_AARCH64_MOVW_UABS_G1=265, + R_AARCH64_MOVW_UABS_G1_NC=266, + R_AARCH64_MOVW_UABS_G2=267, + R_AARCH64_MOVW_UABS_G2_NC=268, + R_AARCH64_MOVW_UABS_G3=269, + R_AARCH64_MOVW_SABS_G0=270, + R_AARCH64_MOVW_SABS_G1=271, + R_AARCH64_MOVW_SABS_G2=272, + R_AARCH64_LD_PREL_LO19=273, + R_AARCH64_ADR_PREL_LO21=274, + R_AARCH64_ADR_PREL_PG_HI21=275, + R_AARCH64_ADR_PREL_PG_HI21_NC=276, + R_AARCH64_ADD_ABS_LO12_NC=277, + R_AARCH64_LDST8_ABS_LO12_NC=278, + R_AARCH64_TSTBR14=279, + R_AARCH64_CONDBR19=280, + R_AARCH64_JUMP26=282, + R_AARCH64_CALL26=283, + R_AARCH64_LDST16_ABS_LO12_NC=284, + R_AARCH64_LDST32_ABS_LO12_NC=285, + R_AARCH64_LDST64_ABS_LO12_NC=286, + R_AARCH64_MOVW_PREL_G0=287, + R_AARCH64_MOVW_PREL_G0_NC=288, + R_AARCH64_MOVW_PREL_G1=289, + R_AARCH64_MOVW_PREL_G1_NC=290, + R_AARCH64_MOVW_PREL_G2=291, + R_AARCH64_MOVW_PREL_G2_NC=292, + R_AARCH64_MOVW_PREL_G3=293, + R_AARCH64_MOVW_GOTOFF_G0=300, + R_AARCH64_MOVW_GOTOFF_G0_NC=301, + R_AARCH64_MOVW_GOTOFF_G1=302, + R_AARCH64_MOVW_GOTOFF_G1_NC=303, + R_AARCH64_MOVW_GOTOFF_G2=304, + R_AARCH64_MOVW_GOTOFF_G2_NC=305, + R_AARCH64_MOVW_GOTOFF_G3=306, + R_AARCH64_GOTREL64=307, + R_AARCH64_GOTREL32=308, + R_AARCH64_GOT_LD_PREL19=309, + R_AARCH64_LD64_GOTOFF_LO15=310, + R_AARCH64_ADR_GOT_PAGE=311, + R_AARCH64_LD64_GOT_LO12_NC=312, + R_AARCH64_TLSGD_ADR_PREL21=512, + R_AARCH64_TLSGD_ADR_PAGE21=513, + R_AARCH64_TLSGD_ADD_LO12_NC=514, + R_AARCH64_TLSGD_MOVW_G1=515, + R_AARCH64_TLSGD_MOVW_G0_NC=516, + R_AARCH64_TLSLD_ADR_PREL21=517, + R_AARCH64_TLSLD_ADR_PAGE21=518, + R_AARCH64_TLSLD_ADD_LO12_NC=519, + R_AARCH64_TLSLD_MOVW_G1=520, + R_AARCH64_TLSLD_MOVW_G0_NC=521, + R_AARCH64_TLSLD_LD_PREL19=522, + R_AARCH64_TLSLD_MOVW_DTPREL_G2=523, + R_AARCH64_TLSLD_MOVW_DTPREL_G1=524, + R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC=525, + R_AARCH64_TLSLD_MOVW_DTPREL_G0=526, + R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC=527, + R_AARCH64_TLSLD_ADD_DTPREL_HI12=528, + R_AARCH64_TLSLD_ADD_DTPREL_LO12=529, + R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC=530, + R_AARCH64_TLSLD_LDST8_DTPREL_LO12=531, + R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC=532, + R_AARCH64_TLSLD_LDST16_DTPREL_LO12=533, + R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC=534, + R_AARCH64_TLSLD_LDST32_DTPREL_LO12=535, + R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC=536, + R_AARCH64_TLSLD_LDST64_DTPREL_LO12=537, + R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC=538, + R_AARCH64_TLSIE_MOVW_GOTTPREL_G1=539, + R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC=540, + R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21=541, + R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC=542, + R_AARCH64_TLSIE_LD_GOTTPREL_PREL19=543, + R_AARCH64_TLSLE_MOVW_TPREL_G2=544, + R_AARCH64_TLSLE_MOVW_TPREL_G1=545, + R_AARCH64_TLSLE_MOVW_TPREL_G1_NC=546, + R_AARCH64_TLSLE_MOVW_TPREL_G0=547, + R_AARCH64_TLSLE_MOVW_TPREL_G0_NC=548, + R_AARCH64_TLSLE_ADD_TPREL_HI12=549, + R_AARCH64_TLSLE_ADD_TPREL_LO12=550, + R_AARCH64_TLSLE_ADD_TPREL_LO12_NC=551, + R_AARCH64_TLSLE_LDST8_TPREL_LO12=552, + R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC=553, + R_AARCH64_TLSLE_LDST16_TPREL_LO12=554, + R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC=555, + R_AARCH64_TLSLE_LDST32_TPREL_LO12=556, + R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC=557, + R_AARCH64_TLSLE_LDST64_TPREL_LO12=558, + R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC=559, + R_AARCH64_COPY=1024, + R_AARCH64_GLOB_DAT=1025, + R_AARCH64_JUMP_SLOT=1026, + R_AARCH64_RELATIVE=1027, + R_AARCH64_TLS_DTPREL64=1028, + R_AARCH64_TLS_DTPMOD64=1029, + R_AARCH64_TLS_TPREL64=1030, + R_AARCH64_TLS_DTPREL32=1031, + R_AARCH64_TLS_DTPMOD32=1032, + R_AARCH64_TLS_TPREL32=1033, +) diff --git a/tools/utils/contrib/elftools/elf/gnuversions.py b/tools/utils/contrib/elftools/elf/gnuversions.py new file mode 100755 index 0000000000..4a4473f3fa --- /dev/null +++ b/tools/utils/contrib/elftools/elf/gnuversions.py @@ -0,0 +1,228 @@ +#------------------------------------------------------------------------------ +# elftools: elf/gnuversions.py +# +# ELF sections +# +# Yann Rouillard (yann@pleiades.fr.eu.org) +# This code is in the public domain +#------------------------------------------------------------------------------ +from ..construct import CString +from ..common.utils import struct_parse, elf_assert +from .sections import Section, Symbol + + +class Version(object): + """ Version object - representing a version definition or dependency + entry from a "Version Needed" or a "Version Dependency" table section. + + This kind of entry contains a pointer to an array of auxiliary entries + that store the information about version names or dependencies. + These entries are not stored in this object and should be accessed + through the appropriate method of a section object which will return + an iterator of VersionAuxiliary objects. + + Similarly to Section objects, allows dictionary-like access to + verdef/verneed entry + """ + def __init__(self, entry, name=None): + self.entry = entry + self.name = name + + def __getitem__(self, name): + """ Implement dict-like access to entry + """ + return self.entry[name] + + +class VersionAuxiliary(object): + """ Version Auxiliary object - representing an auxiliary entry of a version + definition or dependency entry + + Similarly to Section objects, allows dictionary-like access to the + verdaux/vernaux entry + """ + def __init__(self, entry, name): + self.entry = entry + self.name = name + + def __getitem__(self, name): + """ Implement dict-like access to entries + """ + return self.entry[name] + + +class GNUVersionSection(Section): + """ Common ancestor class for ELF SUNW|GNU Version Needed/Dependency + sections class which contains shareable code + """ + + def __init__(self, header, name, stream, elffile, stringtable, + field_prefix, version_struct, version_auxiliaries_struct): + super(GNUVersionSection, self).__init__(header, name, stream) + self.elffile = elffile + self.stringtable = stringtable + self.field_prefix = field_prefix + self.version_struct = version_struct + self.version_auxiliaries_struct = version_auxiliaries_struct + + def num_versions(self): + """ Number of version entries in the section + """ + return self['sh_info'] + + def _field_name(self, name, auxiliary=False): + """ Return the real field's name of version or a version auxiliary + entry + """ + middle = 'a_' if auxiliary else '_' + return self.field_prefix + middle + name + + def _iter_version_auxiliaries(self, entry_offset, count): + """ Yield all auxiliary entries of a version entry + """ + name_field = self._field_name('name', auxiliary=True) + next_field = self._field_name('next', auxiliary=True) + + for _ in range(count): + entry = struct_parse( + self.version_auxiliaries_struct, + self.stream, + stream_pos=entry_offset) + + name = self.stringtable.get_string(entry[name_field]) + version_aux = VersionAuxiliary(entry, name) + yield version_aux + + entry_offset += entry[next_field] + + def iter_versions(self): + """ Yield all the version entries in the section + Each time it returns the main version structure + and an iterator to walk through its auxiliaries entries + """ + aux_field = self._field_name('aux') + count_field = self._field_name('cnt') + next_field = self._field_name('next') + + entry_offset = self['sh_offset'] + for _ in range(self.num_versions()): + entry = struct_parse( + self.version_struct, + self.stream, + stream_pos=entry_offset) + + elf_assert(entry[count_field] > 0, + 'Expected number of version auxiliary entries (%s) to be > 0' + 'for the following version entry: %s' % ( + count_field, str(entry))) + + version = Version(entry) + aux_entries_offset = entry_offset + entry[aux_field] + version_auxiliaries_iter = self._iter_version_auxiliaries( + aux_entries_offset, entry[count_field]) + + yield version, version_auxiliaries_iter + + entry_offset += entry[next_field] + + +class GNUVerNeedSection(GNUVersionSection): + """ ELF SUNW or GNU Version Needed table section. + Has an associated StringTableSection that's passed in the constructor. + """ + def __init__(self, header, name, stream, elffile, stringtable): + super(GNUVerNeedSection, self).__init__( + header, name, stream, elffile, stringtable, 'vn', + elffile.structs.Elf_Verneed, elffile.structs.Elf_Vernaux) + self._has_indexes = None + + def has_indexes(self): + """ Return True if at least one version definition entry has an index + that is stored in the vna_other field. + This information is used for symbol versioning + """ + if self._has_indexes is None: + self._has_indexes = False + for _, vernaux_iter in self.iter_versions(): + for vernaux in vernaux_iter: + if vernaux['vna_other']: + self._has_indexes = True + break + + return self._has_indexes + + def iter_versions(self): + for verneed, vernaux in super(GNUVerNeedSection, self).iter_versions(): + verneed.name = self.stringtable.get_string(verneed['vn_file']) + yield verneed, vernaux + + def get_version(self, index): + """ Get the version information located at index #n in the table + Return boths the verneed structure and the vernaux structure + that contains the name of the version + """ + for verneed, vernaux_iter in self.iter_versions(): + for vernaux in vernaux_iter: + if vernaux['vna_other'] == index: + return verneed, vernaux + + return None + + +class GNUVerDefSection(GNUVersionSection): + """ ELF SUNW or GNU Version Definition table section. + Has an associated StringTableSection that's passed in the constructor. + """ + def __init__(self, header, name, stream, elffile, stringtable): + super(GNUVerDefSection, self).__init__( + header, name, stream, elffile, stringtable, 'vd', + elffile.structs.Elf_Verdef, elffile.structs.Elf_Verdaux) + + def get_version(self, index): + """ Get the version information located at index #n in the table + Return boths the verdef structure and an iterator to retrieve + both the version names and dependencies in the form of + verdaux entries + """ + for verdef, verdaux_iter in self.iter_versions(): + if verdef['vd_ndx'] == index: + return verdef, verdaux_iter + + return None + + +class GNUVerSymSection(Section): + """ ELF SUNW or GNU Versym table section. + Has an associated SymbolTableSection that's passed in the constructor. + """ + def __init__(self, header, name, stream, elffile, symboltable): + super(GNUVerSymSection, self).__init__(header, name, stream) + self.elffile = elffile + self.elfstructs = self.elffile.structs + self.symboltable = symboltable + + def num_symbols(self): + """ Number of symbols in the table + """ + return self['sh_size'] // self['sh_entsize'] + + def get_symbol(self, n): + """ Get the symbol at index #n from the table (Symbol object) + It begins at 1 and not 0 since the first entry is used to + store the current version of the syminfo table + """ + # Grab the symbol's entry from the stream + entry_offset = self['sh_offset'] + n * self['sh_entsize'] + entry = struct_parse( + self.elfstructs.Elf_Versym, + self.stream, + stream_pos=entry_offset) + # Find the symbol name in the associated symbol table + name = self.symboltable.get_symbol(n).name + return Symbol(entry, name) + + def iter_symbols(self): + """ Yield all the symbols in the table + """ + for i in range(self.num_symbols()): + yield self.get_symbol(i) diff --git a/tools/utils/contrib/elftools/elf/relocation.py b/tools/utils/contrib/elftools/elf/relocation.py new file mode 100755 index 0000000000..9d9701ff68 --- /dev/null +++ b/tools/utils/contrib/elftools/elf/relocation.py @@ -0,0 +1,252 @@ +#------------------------------------------------------------------------------- +# elftools: elf/relocation.py +# +# ELF relocations +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +from collections import namedtuple + +from ..common.exceptions import ELFRelocationError +from ..common.utils import elf_assert, struct_parse +from .sections import Section +from .enums import ENUM_RELOC_TYPE_i386, ENUM_RELOC_TYPE_x64, ENUM_RELOC_TYPE_MIPS + + +class Relocation(object): + """ Relocation object - representing a single relocation entry. Allows + dictionary-like access to the entry's fields. + + Can be either a REL or RELA relocation. + """ + def __init__(self, entry, elffile): + self.entry = entry + self.elffile = elffile + + def is_RELA(self): + """ Is this a RELA relocation? If not, it's REL. + """ + return 'r_addend' in self.entry + + def __getitem__(self, name): + """ Dict-like access to entries + """ + return self.entry[name] + + def __repr__(self): + return '' % ( + 'RELA' if self.is_RELA() else 'REL', + self.entry) + + def __str__(self): + return self.__repr__() + + +class RelocationSection(Section): + """ ELF relocation section. Serves as a collection of Relocation entries. + """ + def __init__(self, header, name, stream, elffile): + super(RelocationSection, self).__init__(header, name, stream) + self.elffile = elffile + self.elfstructs = self.elffile.structs + if self.header['sh_type'] == 'SHT_REL': + expected_size = self.elfstructs.Elf_Rel.sizeof() + self.entry_struct = self.elfstructs.Elf_Rel + elif self.header['sh_type'] == 'SHT_RELA': + expected_size = self.elfstructs.Elf_Rela.sizeof() + self.entry_struct = self.elfstructs.Elf_Rela + else: + elf_assert(False, 'Unknown relocation type section') + + elf_assert( + self.header['sh_entsize'] == expected_size, + 'Expected sh_entsize of SHT_REL section to be %s' % expected_size) + + def is_RELA(self): + """ Is this a RELA relocation section? If not, it's REL. + """ + return self.header['sh_type'] == 'SHT_RELA' + + def num_relocations(self): + """ Number of relocations in the section + """ + return self['sh_size'] // self['sh_entsize'] + + def get_relocation(self, n): + """ Get the relocation at index #n from the section (Relocation object) + """ + entry_offset = self['sh_offset'] + n * self['sh_entsize'] + entry = struct_parse( + self.entry_struct, + self.stream, + stream_pos=entry_offset) + return Relocation(entry, self.elffile) + + def iter_relocations(self): + """ Yield all the relocations in the section + """ + for i in range(self.num_relocations()): + yield self.get_relocation(i) + + +class RelocationHandler(object): + """ Handles the logic of relocations in ELF files. + """ + def __init__(self, elffile): + self.elffile = elffile + + def find_relocations_for_section(self, section): + """ Given a section, find the relocation section for it in the ELF + file. Return a RelocationSection object, or None if none was + found. + """ + reloc_section_names = ( + b'.rel' + section.name, + b'.rela' + section.name) + # Find the relocation section aimed at this one. Currently assume + # that either .rel or .rela section exists for this section, but + # not both. + for relsection in self.elffile.iter_sections(): + if ( isinstance(relsection, RelocationSection) and + relsection.name in reloc_section_names): + return relsection + return None + + def apply_section_relocations(self, stream, reloc_section): + """ Apply all relocations in reloc_section (a RelocationSection object) + to the given stream, that contains the data of the section that is + being relocated. The stream is modified as a result. + """ + # The symbol table associated with this relocation section + symtab = self.elffile.get_section(reloc_section['sh_link']) + for reloc in reloc_section.iter_relocations(): + self._do_apply_relocation(stream, reloc, symtab) + + def _do_apply_relocation(self, stream, reloc, symtab): + # Preparations for performing the relocation: obtain the value of + # the symbol mentioned in the relocation, as well as the relocation + # recipe which tells us how to actually perform it. + # All peppered with some sanity checking. + if reloc['r_info_sym'] >= symtab.num_symbols(): + raise ELFRelocationError( + 'Invalid symbol reference in relocation: index %s' % ( + reloc['r_info_sym'])) + sym_value = symtab.get_symbol(reloc['r_info_sym'])['st_value'] + + reloc_type = reloc['r_info_type'] + recipe = None + + if self.elffile.get_machine_arch() == 'x86': + if reloc.is_RELA(): + raise ELFRelocationError( + 'Unexpected RELA relocation for x86: %s' % reloc) + recipe = self._RELOCATION_RECIPES_X86.get(reloc_type, None) + elif self.elffile.get_machine_arch() == 'x64': + if not reloc.is_RELA(): + raise ELFRelocationError( + 'Unexpected REL relocation for x64: %s' % reloc) + recipe = self._RELOCATION_RECIPES_X64.get(reloc_type, None) + elif self.elffile.get_machine_arch() == 'MIPS': + if reloc.is_RELA(): + raise ELFRelocationError( + 'Unexpected RELA relocation for MIPS: %s' % reloc) + recipe = self._RELOCATION_RECIPES_MIPS.get(reloc_type, None) + + if recipe is None: + raise ELFRelocationError( + 'Unsupported relocation type: %s' % reloc_type) + + # So now we have everything we need to actually perform the relocation. + # Let's get to it: + + # 0. Find out which struct we're going to be using to read this value + # from the stream and write it back. + if recipe.bytesize == 4: + value_struct = self.elffile.structs.Elf_word('') + elif recipe.bytesize == 8: + value_struct = self.elffile.structs.Elf_word64('') + else: + raise ELFRelocationError('Invalid bytesize %s for relocation' % + recipe_bytesize) + + # 1. Read the value from the stream (with correct size and endianness) + original_value = struct_parse( + value_struct, + stream, + stream_pos=reloc['r_offset']) + # 2. Apply the relocation to the value, acting according to the recipe + relocated_value = recipe.calc_func( + value=original_value, + sym_value=sym_value, + offset=reloc['r_offset'], + addend=reloc['r_addend'] if recipe.has_addend else 0) + # 3. Write the relocated value back into the stream + stream.seek(reloc['r_offset']) + + # Make sure the relocated value fits back by wrapping it around. This + # looks like a problem, but it seems to be the way this is done in + # binutils too. + relocated_value = relocated_value % (2 ** (recipe.bytesize * 8)) + value_struct.build_stream(relocated_value, stream) + + # Relocations are represented by "recipes". Each recipe specifies: + # bytesize: The number of bytes to read (and write back) to the section. + # This is the unit of data on which relocation is performed. + # has_addend: Does this relocation have an extra addend? + # calc_func: A function that performs the relocation on an extracted + # value, and returns the updated value. + # + _RELOCATION_RECIPE_TYPE = namedtuple('_RELOCATION_RECIPE_TYPE', + 'bytesize has_addend calc_func') + + def _reloc_calc_identity(value, sym_value, offset, addend=0): + return value + + def _reloc_calc_sym_plus_value(value, sym_value, offset, addend=0): + return sym_value + value + + def _reloc_calc_sym_plus_value_pcrel(value, sym_value, offset, addend=0): + return sym_value + value - offset + + def _reloc_calc_sym_plus_addend(value, sym_value, offset, addend=0): + return sym_value + addend + + def _reloc_calc_sym_plus_addend_pcrel(value, sym_value, offset, addend=0): + return sym_value + addend - offset + + # https://dmz-portal.mips.com/wiki/MIPS_relocation_types + _RELOCATION_RECIPES_MIPS = { + ENUM_RELOC_TYPE_MIPS['R_MIPS_NONE']: _RELOCATION_RECIPE_TYPE( + bytesize=4, has_addend=False, calc_func=_reloc_calc_identity), + ENUM_RELOC_TYPE_MIPS['R_MIPS_32']: _RELOCATION_RECIPE_TYPE( + bytesize=4, has_addend=False, + calc_func=_reloc_calc_sym_plus_value), + } + + _RELOCATION_RECIPES_X86 = { + ENUM_RELOC_TYPE_i386['R_386_NONE']: _RELOCATION_RECIPE_TYPE( + bytesize=4, has_addend=False, calc_func=_reloc_calc_identity), + ENUM_RELOC_TYPE_i386['R_386_32']: _RELOCATION_RECIPE_TYPE( + bytesize=4, has_addend=False, + calc_func=_reloc_calc_sym_plus_value), + ENUM_RELOC_TYPE_i386['R_386_PC32']: _RELOCATION_RECIPE_TYPE( + bytesize=4, has_addend=False, + calc_func=_reloc_calc_sym_plus_value_pcrel), + } + + _RELOCATION_RECIPES_X64 = { + ENUM_RELOC_TYPE_x64['R_X86_64_NONE']: _RELOCATION_RECIPE_TYPE( + bytesize=8, has_addend=True, calc_func=_reloc_calc_identity), + ENUM_RELOC_TYPE_x64['R_X86_64_64']: _RELOCATION_RECIPE_TYPE( + bytesize=8, has_addend=True, calc_func=_reloc_calc_sym_plus_addend), + ENUM_RELOC_TYPE_x64['R_X86_64_PC32']: _RELOCATION_RECIPE_TYPE( + bytesize=8, has_addend=True, + calc_func=_reloc_calc_sym_plus_addend_pcrel), + ENUM_RELOC_TYPE_x64['R_X86_64_32']: _RELOCATION_RECIPE_TYPE( + bytesize=4, has_addend=True, calc_func=_reloc_calc_sym_plus_addend), + ENUM_RELOC_TYPE_x64['R_X86_64_32S']: _RELOCATION_RECIPE_TYPE( + bytesize=4, has_addend=True, calc_func=_reloc_calc_sym_plus_addend), + } + + diff --git a/tools/utils/contrib/elftools/elf/sections.py b/tools/utils/contrib/elftools/elf/sections.py new file mode 100755 index 0000000000..1380d6b8e0 --- /dev/null +++ b/tools/utils/contrib/elftools/elf/sections.py @@ -0,0 +1,161 @@ +#------------------------------------------------------------------------------- +# elftools: elf/sections.py +# +# ELF sections +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +from ..common.utils import struct_parse, elf_assert, parse_cstring_from_stream + + +class Section(object): + """ Base class for ELF sections. Also used for all sections types that have + no special functionality. + + Allows dictionary-like access to the section header. For example: + > sec = Section(...) + > sec['sh_type'] # section type + """ + def __init__(self, header, name, stream): + self.header = header + self.name = name + self.stream = stream + + def data(self): + """ The section data from the file. + """ + self.stream.seek(self['sh_offset']) + return self.stream.read(self['sh_size']) + + def is_null(self): + """ Is this a null section? + """ + return False + + def __getitem__(self, name): + """ Implement dict-like access to header entries + """ + return self.header[name] + + def __eq__(self, other): + return self.header == other.header + def __hash__(self): + return hash(self.header) + + +class NullSection(Section): + """ ELF NULL section + """ + def __init__(self, header, name, stream): + super(NullSection, self).__init__(header, name, stream) + + def is_null(self): + return True + + +class StringTableSection(Section): + """ ELF string table section. + """ + def __init__(self, header, name, stream): + super(StringTableSection, self).__init__(header, name, stream) + + def get_string(self, offset): + """ Get the string stored at the given offset in this string table. + """ + table_offset = self['sh_offset'] + s = parse_cstring_from_stream(self.stream, table_offset + offset) + return s + + +class SymbolTableSection(Section): + """ ELF symbol table section. Has an associated StringTableSection that's + passed in the constructor. + """ + def __init__(self, header, name, stream, elffile, stringtable): + super(SymbolTableSection, self).__init__(header, name, stream) + self.elffile = elffile + self.elfstructs = self.elffile.structs + self.stringtable = stringtable + elf_assert(self['sh_entsize'] > 0, + 'Expected entry size of section %r to be > 0' % name) + elf_assert(self['sh_size'] % self['sh_entsize'] == 0, + 'Expected section size to be a multiple of entry size in section %r' % name) + + def num_symbols(self): + """ Number of symbols in the table + """ + return self['sh_size'] // self['sh_entsize'] + + def get_symbol(self, n): + """ Get the symbol at index #n from the table (Symbol object) + """ + # Grab the symbol's entry from the stream + entry_offset = self['sh_offset'] + n * self['sh_entsize'] + entry = struct_parse( + self.elfstructs.Elf_Sym, + self.stream, + stream_pos=entry_offset) + # Find the symbol name in the associated string table + name = self.stringtable.get_string(entry['st_name']) + return Symbol(entry, name) + + def iter_symbols(self): + """ Yield all the symbols in the table + """ + for i in range(self.num_symbols()): + yield self.get_symbol(i) + + +class Symbol(object): + """ Symbol object - representing a single symbol entry from a symbol table + section. + + Similarly to Section objects, allows dictionary-like access to the + symbol entry. + """ + def __init__(self, entry, name): + self.entry = entry + self.name = name + + def __getitem__(self, name): + """ Implement dict-like access to entries + """ + return self.entry[name] + + +class SUNWSyminfoTableSection(Section): + """ ELF .SUNW Syminfo table section. + Has an associated SymbolTableSection that's passed in the constructor. + """ + def __init__(self, header, name, stream, elffile, symboltable): + super(SUNWSyminfoTableSection, self).__init__(header, name, stream) + self.elffile = elffile + self.elfstructs = self.elffile.structs + self.symboltable = symboltable + + def num_symbols(self): + """ Number of symbols in the table + """ + return self['sh_size'] // self['sh_entsize'] - 1 + + def get_symbol(self, n): + """ Get the symbol at index #n from the table (Symbol object). + It begins at 1 and not 0 since the first entry is used to + store the current version of the syminfo table. + """ + # Grab the symbol's entry from the stream + entry_offset = self['sh_offset'] + n * self['sh_entsize'] + entry = struct_parse( + self.elfstructs.Elf_Sunw_Syminfo, + self.stream, + stream_pos=entry_offset) + # Find the symbol name in the associated symbol table + name = self.symboltable.get_symbol(n).name + return Symbol(entry, name) + + def iter_symbols(self): + """ Yield all the symbols in the table + """ + for i in range(1, self.num_symbols() + 1): + yield self.get_symbol(i) diff --git a/tools/utils/contrib/elftools/elf/segments.py b/tools/utils/contrib/elftools/elf/segments.py new file mode 100755 index 0000000000..8b98def516 --- /dev/null +++ b/tools/utils/contrib/elftools/elf/segments.py @@ -0,0 +1,137 @@ +#------------------------------------------------------------------------------- +# elftools: elf/segments.py +# +# ELF segments +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +from ..construct import CString +from ..common.utils import roundup, struct_parse +from ..common.py3compat import bytes2str +from .constants import SH_FLAGS + + +class Segment(object): + def __init__(self, header, stream): + self.header = header + self.stream = stream + + def data(self): + """ The segment data from the file. + """ + self.stream.seek(self['p_offset']) + return self.stream.read(self['p_filesz']) + + def __getitem__(self, name): + """ Implement dict-like access to header entries + """ + return self.header[name] + + def section_in_segment(self, section): + """ Is the given section contained in this segment? + + Note: this tries to reproduce the intricate rules of the + ELF_SECTION_IN_SEGMENT_STRICT macro of the header + elf/include/internal.h in the source of binutils. + """ + # Only the 'strict' checks from ELF_SECTION_IN_SEGMENT_1 are included + segtype = self['p_type'] + sectype = section['sh_type'] + secflags = section['sh_flags'] + + # Only PT_LOAD, PT_GNU_RELR0 and PT_TLS segments can contain SHF_TLS + # sections + if ( secflags & SH_FLAGS.SHF_TLS and + segtype in ('PT_TLS', 'PT_GNU_RELR0', 'PT_LOAD')): + return False + # PT_TLS segment contains only SHF_TLS sections, PT_PHDR no sections + # at all + elif ( (secflags & SH_FLAGS.SHF_TLS) != 0 and + segtype not in ('PT_TLS', 'PT_PHDR')): + return False + + # In ELF_SECTION_IN_SEGMENT_STRICT the flag check_vma is on, so if + # this is an alloc section, check whether its VMA is in bounds. + if secflags & SH_FLAGS.SHF_ALLOC: + secaddr = section['sh_addr'] + vaddr = self['p_vaddr'] + + # This checks that the section is wholly contained in the segment. + # The third condition is the 'strict' one - an empty section will + # not match at the very end of the segment (unless the segment is + # also zero size, which is handled by the second condition). + if not (secaddr >= vaddr and + secaddr - vaddr + section['sh_size'] <= self['p_memsz'] and + secaddr - vaddr <= self['p_memsz'] - 1): + return False + + # If we've come this far and it's a NOBITS section, it's in the segment + if sectype == 'SHT_NOBITS': + return True + + secoffset = section['sh_offset'] + poffset = self['p_offset'] + + # Same logic as with secaddr vs. vaddr checks above, just on offsets in + # the file + return (secoffset >= poffset and + secoffset - poffset + section['sh_size'] <= self['p_filesz'] and + secoffset - poffset <= self['p_filesz'] - 1) + + +class InterpSegment(Segment): + """ INTERP segment. Knows how to obtain the path to the interpreter used + for this ELF file. + """ + def __init__(self, header, stream): + super(InterpSegment, self).__init__(header, stream) + + def get_interp_name(self): + """ Obtain the interpreter path used for this ELF file. + """ + path_offset = self['p_offset'] + return struct_parse( + CString(''), + self.stream, + stream_pos=path_offset) + + +class NoteSegment(Segment): + """ NOTE segment. Knows how to parse notes. + """ + def __init__(self, header, stream, elffile): + super(NoteSegment, self).__init__(header, stream) + self._elfstructs = elffile.structs + + def iter_notes(self): + """ Iterates the list of notes in the segment. + """ + offset = self['p_offset'] + end = self['p_offset'] + self['p_filesz'] + while offset < end: + note = struct_parse( + self._elfstructs.Elf_Nhdr, + self.stream, + stream_pos=offset) + note['n_offset'] = offset + offset += self._elfstructs.Elf_Nhdr.sizeof() + self.stream.seek(offset) + # n_namesz is 4-byte aligned. + disk_namesz = roundup(note['n_namesz'], 2) + note['n_name'] = bytes2str( + CString('').parse(self.stream.read(disk_namesz))) + offset += disk_namesz + + desc_data = bytes2str(self.stream.read(note['n_descsz'])) + if note['n_type'] == 'NT_GNU_ABI_TAG': + note['n_desc'] = struct_parse(self._elfstructs.Elf_Nhdr_abi, + self.stream, + offset) + elif note['n_type'] == 'NT_GNU_BUILD_ID': + note['n_desc'] = ''.join('%.2x' % ord(b) for b in desc_data) + else: + note['n_desc'] = desc_data + offset += roundup(note['n_descsz'], 2) + note['n_size'] = offset - note['n_offset'] + yield note diff --git a/tools/utils/contrib/elftools/elf/structs.py b/tools/utils/contrib/elftools/elf/structs.py new file mode 100755 index 0000000000..d2404ab7b5 --- /dev/null +++ b/tools/utils/contrib/elftools/elf/structs.py @@ -0,0 +1,271 @@ +#------------------------------------------------------------------------------- +# elftools: elf/structs.py +# +# Encapsulation of Construct structs for parsing an ELF file, adjusted for +# correct endianness and word-size. +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +from ..construct import ( + UBInt8, UBInt16, UBInt32, UBInt64, + ULInt8, ULInt16, ULInt32, ULInt64, + SBInt32, SLInt32, SBInt64, SLInt64, + Struct, Array, Enum, Padding, BitStruct, BitField, Value, + ) + +from .enums import * + + +class ELFStructs(object): + """ Accessible attributes: + + Elf_{byte|half|word|word64|addr|offset|sword|xword|xsword}: + Data chunks, as specified by the ELF standard, adjusted for + correct endianness and word-size. + + Elf_Ehdr: + ELF file header + + Elf_Phdr: + Program header + + Elf_Shdr: + Section header + + Elf_Sym: + Symbol table entry + + Elf_Rel, Elf_Rela: + Entries in relocation sections + """ + def __init__(self, little_endian=True, elfclass=32): + assert elfclass == 32 or elfclass == 64 + self.little_endian = little_endian + self.elfclass = elfclass + self._create_structs() + + def _create_structs(self): + if self.little_endian: + self.Elf_byte = ULInt8 + self.Elf_half = ULInt16 + self.Elf_word = ULInt32 + self.Elf_word64 = ULInt64 + self.Elf_addr = ULInt32 if self.elfclass == 32 else ULInt64 + self.Elf_offset = self.Elf_addr + self.Elf_sword = SLInt32 + self.Elf_xword = ULInt32 if self.elfclass == 32 else ULInt64 + self.Elf_sxword = SLInt32 if self.elfclass == 32 else SLInt64 + else: + self.Elf_byte = UBInt8 + self.Elf_half = UBInt16 + self.Elf_word = UBInt32 + self.Elf_word64 = UBInt64 + self.Elf_addr = UBInt32 if self.elfclass == 32 else UBInt64 + self.Elf_offset = self.Elf_addr + self.Elf_sword = SBInt32 + self.Elf_xword = UBInt32 if self.elfclass == 32 else UBInt64 + self.Elf_sxword = SBInt32 if self.elfclass == 32 else SBInt64 + + self._create_ehdr() + self._create_phdr() + self._create_shdr() + self._create_sym() + self._create_rel() + self._create_dyn() + self._create_sunw_syminfo() + self._create_gnu_verneed() + self._create_gnu_verdef() + self._create_gnu_versym() + self._create_note() + + def _create_ehdr(self): + self.Elf_Ehdr = Struct('Elf_Ehdr', + Struct('e_ident', + Array(4, self.Elf_byte('EI_MAG')), + Enum(self.Elf_byte('EI_CLASS'), **ENUM_EI_CLASS), + Enum(self.Elf_byte('EI_DATA'), **ENUM_EI_DATA), + Enum(self.Elf_byte('EI_VERSION'), **ENUM_E_VERSION), + Enum(self.Elf_byte('EI_OSABI'), **ENUM_EI_OSABI), + self.Elf_byte('EI_ABIVERSION'), + Padding(7) + ), + Enum(self.Elf_half('e_type'), **ENUM_E_TYPE), + Enum(self.Elf_half('e_machine'), **ENUM_E_MACHINE), + Enum(self.Elf_word('e_version'), **ENUM_E_VERSION), + self.Elf_addr('e_entry'), + self.Elf_offset('e_phoff'), + self.Elf_offset('e_shoff'), + self.Elf_word('e_flags'), + self.Elf_half('e_ehsize'), + self.Elf_half('e_phentsize'), + self.Elf_half('e_phnum'), + self.Elf_half('e_shentsize'), + self.Elf_half('e_shnum'), + self.Elf_half('e_shstrndx'), + ) + + def _create_phdr(self): + if self.elfclass == 32: + self.Elf_Phdr = Struct('Elf_Phdr', + Enum(self.Elf_word('p_type'), **ENUM_P_TYPE), + self.Elf_offset('p_offset'), + self.Elf_addr('p_vaddr'), + self.Elf_addr('p_paddr'), + self.Elf_word('p_filesz'), + self.Elf_word('p_memsz'), + self.Elf_word('p_flags'), + self.Elf_word('p_align'), + ) + else: # 64 + self.Elf_Phdr = Struct('Elf_Phdr', + Enum(self.Elf_word('p_type'), **ENUM_P_TYPE), + self.Elf_word('p_flags'), + self.Elf_offset('p_offset'), + self.Elf_addr('p_vaddr'), + self.Elf_addr('p_paddr'), + self.Elf_xword('p_filesz'), + self.Elf_xword('p_memsz'), + self.Elf_xword('p_align'), + ) + + def _create_shdr(self): + self.Elf_Shdr = Struct('Elf_Shdr', + self.Elf_word('sh_name'), + Enum(self.Elf_word('sh_type'), **ENUM_SH_TYPE), + self.Elf_xword('sh_flags'), + self.Elf_addr('sh_addr'), + self.Elf_offset('sh_offset'), + self.Elf_xword('sh_size'), + self.Elf_word('sh_link'), + self.Elf_word('sh_info'), + self.Elf_xword('sh_addralign'), + self.Elf_xword('sh_entsize'), + ) + + def _create_rel(self): + # r_info is also taken apart into r_info_sym and r_info_type. + # This is done in Value to avoid endianity issues while parsing. + if self.elfclass == 32: + r_info_sym = Value('r_info_sym', + lambda ctx: (ctx['r_info'] >> 8) & 0xFFFFFF) + r_info_type = Value('r_info_type', + lambda ctx: ctx['r_info'] & 0xFF) + else: # 64 + r_info_sym = Value('r_info_sym', + lambda ctx: (ctx['r_info'] >> 32) & 0xFFFFFFFF) + r_info_type = Value('r_info_type', + lambda ctx: ctx['r_info'] & 0xFFFFFFFF) + + self.Elf_Rel = Struct('Elf_Rel', + self.Elf_addr('r_offset'), + self.Elf_xword('r_info'), + r_info_sym, + r_info_type, + ) + self.Elf_Rela = Struct('Elf_Rela', + self.Elf_addr('r_offset'), + self.Elf_xword('r_info'), + r_info_sym, + r_info_type, + self.Elf_sxword('r_addend'), + ) + + def _create_dyn(self): + self.Elf_Dyn = Struct('Elf_Dyn', + Enum(self.Elf_sxword('d_tag'), **ENUM_D_TAG), + self.Elf_xword('d_val'), + Value('d_ptr', lambda ctx: ctx['d_val']), + ) + + def _create_sym(self): + # st_info is hierarchical. To access the type, use + # container['st_info']['type'] + st_info_struct = BitStruct('st_info', + Enum(BitField('bind', 4), **ENUM_ST_INFO_BIND), + Enum(BitField('type', 4), **ENUM_ST_INFO_TYPE)) + # st_other is hierarchical. To access the visibility, + # use container['st_other']['visibility'] + st_other_struct = BitStruct('st_other', + Padding(5), + Enum(BitField('visibility', 3), **ENUM_ST_VISIBILITY)) + if self.elfclass == 32: + self.Elf_Sym = Struct('Elf_Sym', + self.Elf_word('st_name'), + self.Elf_addr('st_value'), + self.Elf_word('st_size'), + st_info_struct, + st_other_struct, + Enum(self.Elf_half('st_shndx'), **ENUM_ST_SHNDX), + ) + else: + self.Elf_Sym = Struct('Elf_Sym', + self.Elf_word('st_name'), + st_info_struct, + st_other_struct, + Enum(self.Elf_half('st_shndx'), **ENUM_ST_SHNDX), + self.Elf_addr('st_value'), + self.Elf_xword('st_size'), + ) + + def _create_sunw_syminfo(self): + self.Elf_Sunw_Syminfo = Struct('Elf_Sunw_Syminfo', + Enum(self.Elf_half('si_boundto'), **ENUM_SUNW_SYMINFO_BOUNDTO), + self.Elf_half('si_flags'), + ) + + def _create_gnu_verneed(self): + # Structure of "version needed" entries is documented in + # Oracle "Linker and Libraries Guide", Chapter 7 Object File Format + self.Elf_Verneed = Struct('Elf_Verneed', + self.Elf_half('vn_version'), + self.Elf_half('vn_cnt'), + self.Elf_word('vn_file'), + self.Elf_word('vn_aux'), + self.Elf_word('vn_next'), + ) + self.Elf_Vernaux = Struct('Elf_Vernaux', + self.Elf_word('vna_hash'), + self.Elf_half('vna_flags'), + self.Elf_half('vna_other'), + self.Elf_word('vna_name'), + self.Elf_word('vna_next'), + ) + + def _create_gnu_verdef(self): + # Structure off "version definition" entries are documented in + # Oracle "Linker and Libraries Guide", Chapter 7 Object File Format + self.Elf_Verdef = Struct('Elf_Verdef', + self.Elf_half('vd_version'), + self.Elf_half('vd_flags'), + self.Elf_half('vd_ndx'), + self.Elf_half('vd_cnt'), + self.Elf_word('vd_hash'), + self.Elf_word('vd_aux'), + self.Elf_word('vd_next'), + ) + self.Elf_Verdaux = Struct('Elf_Verdaux', + self.Elf_word('vda_name'), + self.Elf_word('vda_next'), + ) + + def _create_gnu_versym(self): + # Structure off "version symbol" entries are documented in + # Oracle "Linker and Libraries Guide", Chapter 7 Object File Format + self.Elf_Versym = Struct('Elf_Versym', + Enum(self.Elf_half('ndx'), **ENUM_VERSYM), + ) + + def _create_note(self): + # Structure of "PT_NOTE" section + self.Elf_Nhdr = Struct('Elf_Nhdr', + self.Elf_word('n_namesz'), + self.Elf_word('n_descsz'), + Enum(self.Elf_word('n_type'), **ENUM_NOTE_N_TYPE), + ) + self.Elf_Nhdr_abi = Struct('Elf_Nhdr_abi', + Enum(self.Elf_word('abi_os'), **ENUM_NOTE_ABI_TAG_OS), + self.Elf_word('abi_major'), + self.Elf_word('abi_minor'), + self.Elf_word('abi_tiny'), + ) diff --git a/tools/utils/elf.py b/tools/utils/elf.py new file mode 100755 index 0000000000..f16358c755 --- /dev/null +++ b/tools/utils/elf.py @@ -0,0 +1,92 @@ +# vim: filetype=python +# Copyright 2019 Autodesk, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from .contrib.elftools.common.exceptions import ELFError +from .contrib.elftools.common.py3compat import bytes2str +from .contrib.elftools.elf.elffile import ELFFile +from .contrib.elftools.elf.dynamic import DynamicSection +from .contrib.elftools.elf.gnuversions import GNUVerSymSection, GNUVerDefSection, GNUVerNeedSection +from .version import Version + +def _get_symbol_version_info(versioninfo, nsym): + ''' + Return a dict containing information on the symbol version + or None if no version information is available + ''' + symbol_version = dict.fromkeys(('index', 'name', 'filename', 'hidden')) + + if not versioninfo['versym'] or nsym >= versioninfo['versym'].num_symbols(): + return None + + symbol = versioninfo['versym'].get_symbol(nsym) + index = symbol.entry['ndx'] + if not index in ['VER_NDX_LOCAL', 'VER_NDX_GLOBAL']: + index = int(index) + + if versioninfo['type'] == 'GNU': + # In GNU versioning mode, the highest bit is used to + # store wether the symbol is hidden or not + if index & 0x8000: + index &= ~0x8000 + symbol_version['hidden'] = True + + if versioninfo['verdef'] and index <= versioninfo['verdef'].num_versions(): + _, verdaux_iter = versioninfo['verdef'].get_version(index) + symbol_version['name'] = bytes2str(next(verdaux_iter).name) + else: + verneed, vernaux = versioninfo['verneed'].get_version(index) + symbol_version['name'] = bytes2str(vernaux.name) + symbol_version['filename'] = bytes2str(verneed.name) + + symbol_version['index'] = index + return symbol_version + + +def get_maximum_symbol_version(filename): + ''' + Return a dict containing information about the maximum versioned symbols in the library + ''' + with open(filename, 'rb') as file: + sv = {} + try: + versioninfo = {'versym': None, 'verdef': None, 'verneed': None, 'type': None} + elf_file = ELFFile(file) + for section in elf_file.iter_sections(): + if isinstance(section, GNUVerSymSection ): versioninfo['versym'] = section + elif isinstance(section, GNUVerDefSection ): versioninfo['verdef'] = section + elif isinstance(section, GNUVerNeedSection): versioninfo['verneed'] = section + elif isinstance(section, DynamicSection ): + for tag in section.iter_tags(): + if tag['d_tag'] == 'DT_VERSYM': + versioninfo['type'] = 'GNU' + break + + if not versioninfo['type'] and (versioninfo['verneed'] or versioninfo['verdef']): + versioninfo['type'] = 'Solaris' + + if not versioninfo['type'] or not versioninfo['versym']: + return sv + + for idx in xrange(versioninfo['versym'].num_symbols()): + symbol_version = _get_symbol_version_info(versioninfo, idx) + if symbol_version['index'] not in ['VER_NDX_LOCAL', 'VER_NDX_GLOBAL']: + version = symbol_version['name'].partition('_') + if version[1] == '_' and version[2]: + prefix = version[0] + version = Version(version[2]) + if version > sv.get(prefix, Version(None)): + sv[prefix] = version + return sv + except ELFError as ex: + return sv diff --git a/tools/utils/external.py b/tools/utils/external.py new file mode 100755 index 0000000000..aeacc12928 --- /dev/null +++ b/tools/utils/external.py @@ -0,0 +1,136 @@ +# vim: filetype=python +# Copyright 2019 Autodesk, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os +from SCons.Script import * + +from . import system +from . import compiler +from . import elf +from .version import Version + +def detect_glibc_version (env, bin): return compiler.detect_version(env, bin, ['__GLIBC__','__GLIBC_MINOR__']) +def detect_libstdcxx_version(env, bin): + if system.is_linux: + s, o = system.execute([bin, '-print-file-name=libstdc++.so'], env=env['ENV']) + if s == 0 and len(o) == 1: + try: + return elf.get_maximum_symbol_version(o[0]).get('GLIBCXX', Version(None)) + except: + pass + return Version(None) + +def configure(env): + ## Create a dictionary of all our libs so we can pass them around + ## to child SConscript's easily + libs = {} + + # Determine the internal name of the external libraries, the path under the + # contrib folder, and the libraries we will be linking + ext_config = ( + # name , location , library + ('oiio' , 'OpenImageIO', 'OpenImageIO' ), + ('ocio' , 'OpenColorIO', 'OpenColorIO' ), + ('tcmalloc', 'tcmalloc' , 'tcmalloc_minimal'), + ('rlm' , 'rlm' , 'rlm.a' if not system.is_windows else 'rlmclient_md gdi32 wbemuuid.lib'), + ('clm' , 'clm' , 'AdClmHub' + ('_1' if system.is_windows else '')), + ('pit' , 'pit' , 'adlmPIT'), + ('m_intel' , 'IntelC++' , 'libimf.a libirc.a' if not system.is_windows else 'libmmds.lib libirc.lib svml_dispmt.lib'), + ('m_amd' , 'amdlibm' , 'amdlibm'), + ('m_system', '' , 'm'), + ('tbb' , 'tbb' , 'tbb'), + ('blosc' , 'blosc' , 'blosc'), + ('boost' , 'boost' , 'boost_iostreams'), + ('openvdb' , 'openvdb' , 'openvdb'), + ('zlib' , 'zlib' , ''), + ('curl' , 'curl' , 'libcurl.a' if not system.is_windows else 'libcurl.lib ssleay32.lib libeay32.lib libssh2.lib Crypt32.lib Wldap32.lib'), + ) + # We don't need to link to the following libraries + ext_no_needs_link = ('zlib',) + # Add the previous libraries to the "libs" dictionary + for ext, ext_loc, ext_lib in ext_config: + if ext in ['clm', 'pit'] and not env['USE_CLM']: + continue + ext_incpath = os.path.join('#contrib', ext_loc, 'include') + ext_libpath = os.path.join('#contrib', ext_loc, 'lib', system.os) + ext_incpath = ext_incpath if os.path.exists(Dir(ext_incpath).abspath) else '' + ext_libpath = ext_libpath if os.path.exists(Dir(ext_libpath).abspath) else '' + libs[ext] = ExternalLibrary(ext_lib, ext_incpath, ext_libpath, '', '', (ext not in ext_no_needs_link)) + + if env['USE_OSL']: + osl_includepath = '#contrib/OSL/include' + osl_libpath = '#contrib/OSL/lib/%s' % system.os + osl_binpath = '#contrib/OSL/bin/%s' % system.os + libs['osl'] = ExternalLibrary('oslexec oslquery oslcomp', osl_includepath, osl_libpath, defines='OSL_STATIC_BUILD OIIO_STATIC_BUILD') + + if system.is_windows: + libs['dbghelp'] = ExternalLibrary('Dbghelp') + libs['gl'] = ExternalLibrary('opengl32') + if env['USE_AZURE']: + libs['curl'].defines = 'CURL_STATICLIB' + elif system.is_linux: + libs['pthread'] = ExternalLibrary('pthread') + libs['X11'] = ExternalLibrary('X11 xcb Xau') + libs['gl'] = ExternalLibrary('GL', needs_link=False) + libs['dl'] = ExternalLibrary('dl') + # real time extensions library is needed for python to find libai.so + libs['rt'] = ExternalLibrary('rt') + # needed for __builtin_cpu_supports on some systems, see #5662 + libs['gcc'] = ExternalLibrary('gcc') + elif system.is_darwin: + libs['pthread'] = ExternalLibrary('pthread') + + env['EXTLIBS'] = libs + + # we globally choose the "math" library between either libimf, amdlibm+m, or + # none of them + if env['LIBM'] != 'none': + env['EXTLIBS']['m_{}'.format(env['LIBM'])].attach(env) + + +## this class will represent the use of a 3rd party library +class ExternalLibrary: + def __init__(self, libs, includepath='', libpath='', defines='', linkflags='', needs_link=True): + ## the name of the lib is the only required argument + self.libs = libs + + ## all of these are optional + self.defines = defines + self.includepath = includepath + self.libpath = libpath + self.linkflags = linkflags + self.needs_link = needs_link + + ## Attach this library to the specific environment + def attach(self, env): + ## Configure the compiler + if self.defines != '': + ## configure the preprocessor + env.Append(CPPDEFINES=env.Split(self.defines)) + if self.includepath != '': + ## configure the path to the headers + env.Append(CPPPATH=env.Split(self.includepath)) + + ## defer the linker config to this other method + self.linkwith(env) + + def linkwith(self, env): + ## Configure the linker + if self.needs_link: + env.Append(LIBS=env.Split(self.libs)) + if self.libpath != '': + ## configure the path to the libraries + env.Append(LIBPATH=env.Split(self.libpath)) + if self.linkflags != '': + env.Append(LINKFLAGS=env.Split(self.linkflags)) diff --git a/tools/utils/git.py b/tools/utils/git.py new file mode 100755 index 0000000000..e1ea8143bf --- /dev/null +++ b/tools/utils/git.py @@ -0,0 +1,115 @@ +# vim: filetype=python +# Copyright 2019 Autodesk, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from . import system +from .version import Version + +def check(): + ''' + Check for Git existence + ''' + cmd = ['git', '--version'] + r, o = system.execute(cmd) + return r == 0 + +def version(): + ''' + Return the Git version + ''' + cmd = ['git', '--version'] + r, o = system.execute(cmd) + print r + return Version(o[0].split()[-1]) + +def uncommitted(): + ''' + Check for uncommitted changes in the index + ''' + cmd = ['git', 'diff', '--quiet', '--ignore-submodules', '--cached'] + r, o = system.execute(cmd) + return r != 0 + +def unstaged(): + ''' + Check for unstaged changes + ''' + cmd = ['git', 'diff-files', '--quiet', '--ignore-submodules'] + r, o = system.execute(cmd) + return r != 0 + +def untracked(): + ''' + Check for untracked files + ''' + cmd = ['git', 'ls-files', '--others', '--exclude-standard'] + r, o = system.execute(cmd) + return len(o) > 0 if r == 0 else False + +def stashed(): + ''' + Check for stashed changes + ''' + return sha1('refs/stash') is not None + +def branch(): + ''' + Return the short symbolic-ref of the branch where the HEAD is attached. If + the HEAD is dettached, return None + ''' + cmd = ['git', 'symbolic-ref', '--short', '-q', 'HEAD'] + r, o = system.execute(cmd) + return o[0] if r == 0 else None + +def remote_url(remote='origin'): + cmd = ['git', 'config', '--get', 'remote.{}.url'.format(remote)] + r, o = system.execute(cmd) + return o[0] if r == 0 else None + +def sha1(obj='HEAD'): + cmd = ['git', 'rev-parse', '--verify', obj] + r, o = system.execute(cmd) + return o[0] if r == 0 else None + +def tags(obj='HEAD'): + ''' + Return the list of tags that are pointing to "obj" + ''' + cmd = ['git', 'tag', '--points-at', sha1(obj)] + r, o = system.execute(cmd) + return o if r == 0 else [] + +def parents(obj='HEAD'): + ''' + Return the list of "obj"'s parent commits + ''' + cmd = ['git', 'rev-list', '--parents', '-n 1', obj] + r, o = system.execute(cmd) + return o[0].split()[1:] if r == 0 else [] + +def children(obj='HEAD'): + ''' + Return the list of "obj"'s children commits + ''' + cmd = ['git', 'rev-list', '--parents', '--all'] + r, o = system.execute(cmd) + if r == 0: + # Split every line in "line_s" and group by (commit, parent commits) in + # "line_g" + lines_s = (x.split() for x in o) + lines_g = ((x[0], x[1:]) for x in lines_s) + commit_sha1 = sha1(obj) + # "commit" will be a child if "commit_sha1" is among the parents + return [commit for commit, parents in lines_g if commit_sha1 in parents] + else: + return [] diff --git a/tools/utils/path.py b/tools/utils/path.py new file mode 100755 index 0000000000..0bb346893c --- /dev/null +++ b/tools/utils/path.py @@ -0,0 +1,54 @@ +# vim: filetype=python +# Copyright 2019 Autodesk, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os, shutil + +def list(path, extensions=None): + ''' + Returns a list of all files with an extension from the 'extensions' list + ''' + path = os.path.normpath(path) + result = [] + for root, dirs, files in os.walk(path): + if '.git' in dirs: + dirs.remove('.git') + for f in files: + if not extensions or os.path.splitext(f)[1] in extensions: + # Build the absolute path and then remove the root path, to get the relative path from root + result.append(os.path.join(root, f)[len(path) + 1:]) + result.sort(key=os.path.split) ## keep the files in a predictable order + return result + +def remove(path): + ''' + Handy function to remove files only if they exist + ''' + if os.path.exists(path): + if os.path.isdir(path): + shutil.rmtree(path) + else: + os.remove(path) + +def copy(src, target): + ''' + Copies a file or a symbolic link (creating a new link in the target dir) + ''' + if os.path.isdir(target): + target = os.path.join(target, os.path.basename(src)) + + if os.path.islink(src): + linked_path = os.readlink(src) + os.symlink(linked_path, target) + else: + shutil.copy(src, target) diff --git a/tools/utils/regression_test.py b/tools/utils/regression_test.py new file mode 100755 index 0000000000..76bb3a5f5e --- /dev/null +++ b/tools/utils/regression_test.py @@ -0,0 +1,202 @@ +# Copyright 2019 Autodesk, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os, glob + +from SCons.Script import * + +from . import system + +# Set NOCRASH string for tests which we don't want to debug on crash (Windows only) +NOCRASH = '' +if system.is_windows: + NOCRASH = '-nocrashpopup' + +testsuite_common = os.path.abspath(os.path.join('testsuite', 'common')) + +class Test: + def __init__(self, + script = None, # To be set later in prepare_test + plugin_sources = '*.c*', + program_sources = '', + program_name = 'test', + plugin_dependencies = '', + output_image = 'testrender.tif', ## can be '' if the test does not generate an image + reference_image = '', + progressive = False, + kick_params = '', + resaved = False, + forceexpand = False, + scene = 'test.ass', + diff_hardfail = 0.0157, ## (4/256) oiiotool option --hardfail + diff_fail = 0.00001, ## (<1/256) oiiotool option --fail + diff_failpercent = 33.334, ## oiiotool option --failpercent + diff_warnpercent = 0.0, ## oiiottol option --warnpercent + make_thumbnails = True, ## generate images for html display (needs to be disabled for formats with no conversion to 2D image, like deepexr) + environment = [], ## environment variables set before the script is run + continue_on_failure = False, ## if this is a multi-command test, keep running even if one of the early stages fails (crashes) + force_result = 'OK'): + ## save the params + self.script = script + self.plugin_sources = plugin_sources + self.program_sources = program_sources + self.program_name = program_name + self.plugin_dependencies = plugin_dependencies + self.output_image = output_image + self.reference_image = reference_image + self.progressive = progressive + self.kick_params = kick_params + self.resaved = resaved + self.forceexpand = forceexpand + self.scene = scene + self.diff_hardfail = diff_hardfail + self.diff_fail = diff_fail + self.diff_failpercent = diff_failpercent + self.diff_warnpercent = diff_warnpercent + self.make_thumbnails = make_thumbnails + self.environment = environment + self.continue_on_failure = continue_on_failure + self.force_result = force_result + + @staticmethod + def CreateTest(test, locals): + params = dict() + with open(os.path.join('testsuite', test, 'README'), 'r') as f: + readme = f.read() + index = readme.find('PARAMS:') + if index != -1: + params = eval(readme[index + 8:], globals(), locals) + return Test(**params) + + # This function is called when the script was not especified (self.script is null) + def generate_command_line(self, test_dir): + params = ['-dw', '-r 160 120', '-bs 16'] + + params += { + '.exr' : ['-o %s' % self.output_image], + '.tif' : ['-o %s' % self.output_image, '-set driver_tiff.dither false'] + }.get(os.path.splitext(self.output_image)[1], []) + + params.append(NOCRASH) + + if not self.progressive: + params.append('-dp') + + if self.kick_params: + if isinstance(self.kick_params, basestring): + params.append(self.kick_params) + else: + params.extend(self.kick_params) + + if self.resaved: + forceexpand = '-forceexpand' if self.forceexpand else '' + self.script = 'kick %s %s -resave test_resaved.ass\n' % (self.scene, forceexpand) + ' '.join(['kick test_resaved.ass'] + params) + else: + self.script = ' '.join(['kick %s' % self.scene] + params) + + def prepare_test(self, test_name, env): + # Silence test preparation by globally overriding the paramater PRINT_CMD_LINE_FUNC + # in this current SCons sub-environment, used in target generation (Program(), + # SharedLibrary(), Install(), etc.). + env['PRINT_CMD_LINE_FUNC'] = lambda s, target, src, env : None + + test_dir = os.path.join(env.Dir('.').srcnode().abspath, test_name) + test_data_dir = os.path.join(test_dir, 'data') + test_build_dir = os.path.join(env.Dir('.').abspath, test_name) + + env.VariantDir(test_build_dir, test_data_dir) + + if os.path.exists(os.path.join(test_data_dir, 'test.cpp')): + if not self.script: + self.script = os.path.join(test_build_dir, 'test') + self.program_name = 'test' + self.program_sources = 'test.cpp' + + if os.path.exists(os.path.join(test_data_dir, 'test.py')): + if not self.script: + self.script = './test.py' + + # If reference_image was not specified, try to guess from existing files + if not self.reference_image: + if os.path.exists(os.path.join(test_dir, 'ref', 'reference.exr')): + self.reference_image = os.path.join('ref', 'reference.exr') + self.output_image = 'testrender.exr' + elif os.path.exists(os.path.join(test_dir, 'ref', 'reference.tif')): + self.reference_image = os.path.join('ref', 'reference.tif') + + # If an execution command line was not specified or generated, set the default one + if not self.script: + self.generate_command_line(test_dir) + + ## process the current test directory + ## Step 1: build any shaders/procedurals that might exist + SHADERS = [] + if self.plugin_sources.find('*') == -1: + ## just a list of regular file names + shader_files = [os.path.join(test_data_dir, shader) for shader in Split(self.plugin_sources) if shader != 'test.cpp'] + else: + ## use recursive glob pattern + shader_files = [] + for root, dirs, files in os.walk(test_data_dir): + if '.svn' in dirs: + dirs.remove('.svn') + for pattern in Split(self.plugin_sources): + shader_files += [f for f in glob.glob(os.path.join(root, pattern)) if not os.path.basename(f) == 'test.cpp'] + for shader_file in shader_files: + BUILD_SHADER_FILE = shader_file.replace(test_data_dir, test_build_dir) + t = env.SharedLibrary(os.path.splitext(BUILD_SHADER_FILE)[0], BUILD_SHADER_FILE) + env.Depends(t, LIBAI) + SHADERS += t + if self.program_sources != '': + ## we need to build a program + t = env.Program(os.path.join(test_build_dir, self.program_name), [os.path.join(test_build_dir, f) for f in Split(self.program_sources)]) + env.Depends(t, LIBAI) + SHADERS += t + FILES = [] + FILES += env.Install(test_build_dir, os.path.join(test_dir, 'README')) + + for root, dirs, files in os.walk(test_data_dir): + if '.svn' in dirs: + dirs.remove('.svn') + for f in files: + if os.path.basename(f) == 'Makefile': + continue + if os.path.splitext(f)[1] == 'c': + continue + if os.path.splitext(f)[1] == 'cpp': + continue + d = root + d = d.replace(test_data_dir, test_build_dir) + FILES += env.Install(d, os.path.join(root, f)) + + ## generate the build action that will run the test and produce the html output + test_target = env.RunTest(os.path.join(test_build_dir, test_name + '.html'), FILES + SHADERS, + TEST_SCRIPT = self.script, + REFERENCE_IMAGE = self.reference_image != '' and os.path.join(test_dir, self.reference_image) or '', + OUTPUT_IMAGE = self.output_image, + MAKE_THUMBNAILS = self.make_thumbnails, + DIFF_HARDFAIL = self.diff_hardfail, + DIFF_FAIL = self.diff_fail, + DIFF_FAILPERCENT = self.diff_failpercent, + DIFF_WARNPERCENT = self.diff_warnpercent, + FORCE_RESULT = self.force_result, + CONTINUE_ON_FAILURE = self.continue_on_failure, + TEST_NAME = test_name, + ENVIRONMENT = self.environment, + PRINT_CMD_LINE_FUNC = lambda a, b, c, d : None, ## silence the builder + chdir = 0) + + env.AlwaysBuild(test_target) + env.Alias(test_name, test_target) + + return test_target # The test has been prepared and can be run diff --git a/tools/utils/system.py b/tools/utils/system.py new file mode 100755 index 0000000000..1f09f971f4 --- /dev/null +++ b/tools/utils/system.py @@ -0,0 +1,132 @@ +# vim: filetype=python +# Copyright 2019 Autodesk, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import platform +import collections +import shlex +import subprocess +import sys +import time + +# Obtain information about the system only once, when loaded +os = platform.system().lower() + +_linux = 'linux' +_darwin = 'darwin' +_windows = 'windows' + +_Allowed = collections.namedtuple('_Allowed', ['os']) + +# allowed.os is a list of allowed operative system +allowed = _Allowed( + os = [_linux, _darwin, _windows] +) + +# These data avoid writing error prone checks like "os.system.os == 'linux'" +is_linux = os == _linux +is_darwin = os == _darwin +is_windows = os == _windows + +IS_LINUX = is_linux +IS_DARWIN = is_darwin +IS_WINDOWS = is_windows + +PATH = 'PATH' +LIBRARY_PATH = { + _linux : 'LD_LIBRARY_PATH', + _darwin : 'DYLD_LIBRARY_PATH', + _windows: 'PATH', +}.get(os, None) +PYTHON_PATH = 'PYTHONPATH' +ARNOLD_PLUGIN_PATH = 'ARNOLD_PLUGIN_PATH' +LIB_EXTENSION = { + _linux: '.so', + _darwin: '.dylib', + _windows: '.dll', +}.get(os, '') + +# This "safe" version of "print" works atomically, avoiding the mess caused by +# multiple threads writing at the same time. It has the same declaration and +# behavior as the Python 3.3 print() function: +# https://docs.python.org/3/library/functions.html?highlight=print#print +def print_safe(*args, **kwargs): + # Check input parameters + valid_kwargs = ('sep', 'end', 'file', 'flush') + for key, value in kwargs.iteritems(): + if key not in valid_kwargs: + raise TypeError('\'{}\' is an invalid keyword argument for this function'.format(key)) + elif key in ['sep', 'end']: + not_string = not isinstance(value, basestring) + not_None = value is not None + if not_string and not_None: + typename = type(value).__name__ + raise TypeError('\'{}\' must be None or a string, not {}'.format(key, typename)) + # Transform objects into string + objects = (str(o) for o in args) + # Get input parameters + sep = kwargs.get('sep') + end = kwargs.get('end') + fhd = kwargs.get('file') + ffl = kwargs.get('flush', False) + # Set default values if not provided + sep = ' ' if sep is None else sep + end = '\n' if end is None else end + fhd = sys.stdout if fhd is None else fhd + # Write the whole string and flush if requested + fhd.write(sep.join(objects) + end) + if ffl: + fhd.flush() + +def execute(cmd, env=None, cwd=None, verbose=False, shell=False, callback=lambda line: None, timeout=0): + ''' + Executes a command and returns a tuple with the exit code and the output + ''' + # Things to do before executing the command: + # - Split cmd into a list if it is a string + # - Initialize the output and return codes + # - Normalize environment to strings + c = shlex.split(cmd, posix=(not is_windows)) if (type(cmd) == str) and not shell else cmd + r, o = 0, [] + e = {k : str(v) for k, v in env.items()} if env else None + # Create a dictionary with the arguments for subprocess.Popen() + popen_args = { + 'args' : c, + 'stdout' : subprocess.PIPE, + 'stderr' : subprocess.STDOUT, + 'cwd' : cwd, + 'env' : e, + 'shell' : shell, + 'bufsize' : 1, + 'universal_newlines': True, + } + try: + t = time.time() + p = subprocess.Popen(**popen_args) + with p.stdout: + for line in iter(p.stdout.readline, b''): + if not line: + break + elif timeout and (time.time() - t) > timeout: + p.kill() + break + line = line.rstrip('\n') + o.append(line) + callback(line) + if verbose: + print(line) + r = p.wait() + except OSError as e: + o = [e.strerror] + r = e.errno + return (r, o) diff --git a/tools/utils/test_stats.py b/tools/utils/test_stats.py new file mode 100755 index 0000000000..55f2cc8393 --- /dev/null +++ b/tools/utils/test_stats.py @@ -0,0 +1,251 @@ +# vim: filetype=python +# Copyright 2019 Autodesk, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os, shutil, string, platform, subprocess +from os import popen +import time +import shlex, subprocess + +from . import path + +# +# TimedTest class is a placeholder to store data about a timed test +# +class TimedTest: + def __init__(self, timing = None): + if timing: + self.tested = True + self._timing = timing + else: + self.tested = False + + def get_timing(self): + return self._timing + + def set_timing(self, val): + self.tested = True + self._timing = val + + timing = property(get_timing, set_timing) + +# +# TimedTestTable behaves like a DB table. It stores in each record a +# testsuite run, along with a timestamp. The table is able to load and +# save its state as a text file. +# +class TimedTestTable: + def __init__(self, base_dir = os.path.abspath('.')): + self._base_dir = base_dir + self._mintest = 1000000 + self._maxtest = -1 + self._data = [] + self._timestamp = [] + + def reset(self): + self._mintest = 1000000 + self._maxtest = -1 + self._data = [] + self._timestamp = [] + + # Create a new record in the table, bookmarked with a timestamp + def timestamp(self, ts = None): + if ts: + self._timestamp.append(ts) + else: + self._timestamp.append(time.strftime('%Y%m%d%H%M%S', time.gmtime())) + n_timestamp = len(self._data) + if n_timestamp == 0: + self._data.append([]) + elif n_timestamp > 0: + self._data.append( (self._maxtest + 1) * [ TimedTest() ] ) + + # Add a new test with its timing info in the current timestamped record + def add(self, test, timing): + if test < self._mintest: + self._mintest = test + if test > self._maxtest: + n_to_add = test - self._maxtest + for i in range(len(self._data)): + for j in range(n_to_add): + self._data[i].append( TimedTest() ) + self._maxtest = test + self._data[-1][test] = TimedTest(timing) + + # Save the table in a file + def save(self): + with open(os.path.join(self._base_dir, 'stats.db'), 'w') as f: + for i in range(len(self._data)): + f.write('%s ' % self._timestamp[i]) + for j in range(self._maxtest + 1): + if self._data[i][j].tested: + f.write('%f ' % self._data[i][j].timing) + else: + f.write('X ') + f.write('\n') + + # Load the table from a file + def load(self): + self.reset() + try: + with open(os.path.join(self._base_dir, 'stats.db'), 'r') as f: + file_lines = f.readlines() + for i in range(len(file_lines)): + file_lines[i] = file_lines[i].split() + self.timestamp(file_lines[i][0]) + for j in range(1, len(file_lines[i])): + if file_lines[i][j] != 'X': + self.add(j-1, float(file_lines[i][j])) + except IOError: + return + + # Compute the stats of a given test (from all the execution history) + def compute_stats(self, test): + min = 1000000.0 + max = -1000000.0 + sum = 0.0 + mean = 0.0 + q25 = 0 + median = 0 + q75 = 0 + speedup = 1 + tested = 0 + times = [] + for i in range(len(self._data)): + if self._data[i][test].tested: + tm = self._data[i][test].timing + times.append(tm) + tested = tested + 1 + sum = sum + tm + if tm < min: + min = tm + if tm > max: + max = tm + if tested > 1: + speedup = times[-2] / times[-1] + else: + speedup = 1 + if tested > 0: + mean = sum / tested + times.sort() + q25 = times[ int(tested * 0.25) ] + median = times[ int(tested * 0.5 ) ] + q75 = times[ int(tested * 0.75) ] + + return (tested, min, max, mean, q25, median, q75, speedup) + + # Generate statistical plots about the testsuite + def generate_plots(self): + plot_command = 'gnuplot' + mintestex = self._maxtest + 1 + maxtestex = 0 + for i in range(self._maxtest + 1): + if self._data[-1][i].tested: + if i < mintestex: + mintestex = i + if i > maxtestex: + maxtestex = i + + test_stats = [] + for i in range(self._maxtest + 1): + test_stats.append(self.compute_stats(i)) + + f_filename = os.path.join(self._base_dir, 'plot.data.tmp') + with open(f_filename, 'w') as f: + for i in range(self._maxtest + 1): + tested, min, max, mean, q25, median, q75, speedup = test_stats[i] + if tested and self._data[-1][i].tested: + f.write('''%.4d %f %f %f %f %f %f %f %f\n''' % (i, min, q25, mean, q75, max, median, speedup, self._data[-1][i].timing)) + + # Generate a Histogram (Last Executed Testsuite) + gnuplot_process = subprocess.Popen(shlex.split(plot_command), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + gnuplot = gnuplot_process.stdin + + gnuplot.write('''set xrange [%f:%f]\n''' % (mintestex-0.5, maxtestex+0.5)) + gnuplot.write('''set xtics 0, %d\n''' % (maxtestex - mintestex <= 100 and 10 or 100 )) + gnuplot.write('''set grid x\n''') + gnuplot.write('''set grid y\n''') + gnuplot.write('''set style line 1 lw 1 lc rgb \"#23b323\"\n''') + gnuplot.write('''set style line 2 lw 1 lc rgb \"#e41919\"\n''') + gnuplot.write('''set style line 3 lw 1 lc rgb \"#000000\"\n''') + gnuplot.write('''set style data histogram\n''') + gnuplot.write('''set style fill solid noborder\n''') + gnuplot.write('''set boxwidth 0.95\n''') + gnuplot.write('''set terminal png size 1024,400\n''') + gnuplot.write('''set output \'%s\'\n''' % os.path.join(self._base_dir, 'plot_rt-sup.png')) + + gnuplot.write('''set multiplot\n''') + + gnuplot.write('''set nokey\n''') + gnuplot.write('''set xlabel\"\"\n''') + gnuplot.write('''set ylabel\"Running time (seconds)\"\n''') + gnuplot.write('''set ytics add (\"\" 0)\n''') + gnuplot.write('''set size 1, 0.5\n''') + gnuplot.write('''set origin 0, 0.5\n''') + gnuplot.write('''set bmargin 0\n''') + gnuplot.write('''set lmargin 10\n''') + gnuplot.write('''set rmargin 2\n''') + gnuplot.write('''set format x \"\"\n''') + gnuplot.write('''set format y \"%.2f s\"\n''') + gnuplot.write('''plot ''') + gnuplot.write('''\'%s\' using 1:9 with boxes lt 3''' % f_filename) + gnuplot.write('''\n''') + + gnuplot.write('''set nokey\n''') + gnuplot.write('''set xlabel\"Tests\"\n''') + gnuplot.write('''set ylabel\"Speedup\"\n''') + gnuplot.write('''unset ytics\n''') + gnuplot.write('''set ytics autofreq\n''') + gnuplot.write('''set size 1, 0.5\n''') + gnuplot.write('''set origin 0, 0.0\n''') + gnuplot.write('''set bmargin\n''') + gnuplot.write('''set tmargin 0\n''') + gnuplot.write('''set format x\n''') + gnuplot.write('''set format y \"x %.2f\"\n''') + gnuplot.write('''plot ''') + gnuplot.write('''\'%s\' using 1:($8>1?1:1/0):($8>1?1:1/0):($8>1?$8:1/0):($8>1?$8:1/0) with candlesticks lt 2 lw 1 whiskerbars''' % f_filename) + gnuplot.write(''',''') + gnuplot.write('''\'%s\' using 1:($8>1?1/0:$8):($8>1?1/0:$8):($8>1?1/0:1):($8>1?1/0:1) with candlesticks lt 1 lw 1 whiskerbars''' % f_filename) + gnuplot.write(''',''') + gnuplot.write('''1 with lines ls 3''') + gnuplot.write('''\n''') + + gnuplot.write('''exit\n''') + gnuplot_process.wait() + + # Generate a BoxPlot + gnuplot_process = subprocess.Popen(shlex.split(plot_command), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + gnuplot = gnuplot_process.stdin + + gnuplot.write('''set xlabel\"Tests\"\n''') + gnuplot.write('''set ylabel\"Running time (seconds)\"\n''') + gnuplot.write('''set xrange [%f:%f]\n''' % (mintestex-0.5, maxtestex+0.5)) + gnuplot.write('''set xtics 0, %d\n''' % (maxtestex - mintestex <= 100 and 10 or 100 )) + gnuplot.write('''set grid x\n''') + gnuplot.write('''set grid y\n''') + gnuplot.write('''set style line 1 lw 1 lc rgb \"#23b323\"\n''') + gnuplot.write('''set style line 2 lw 1 lc rgb \"#e41919\"\n''') + gnuplot.write('''set style fill solid noborder\n''') + gnuplot.write('''set boxwidth 0.95\n''') + gnuplot.write('''set terminal png size 1024,256\n''') + gnuplot.write('''set output \'%s\'\n''' % os.path.join(self._base_dir, 'plot_bp.png')) + gnuplot.write('''plot ''') + gnuplot.write('''\'%s\' using 1:3:2:4:4 with candlesticks ls 2 whiskerbars''' % f_filename) + gnuplot.write(''',''') + gnuplot.write('''\'%s\' using 1:4:4:6:5 with candlesticks ls 1 whiskerbars''' % f_filename) + gnuplot.write('''\n''') + + gnuplot.write('''exit\n''') + gnuplot_process.wait() + + path.remove(f_filename) diff --git a/tools/utils/testsuite.py b/tools/utils/testsuite.py new file mode 100755 index 0000000000..c260b1c7be --- /dev/null +++ b/tools/utils/testsuite.py @@ -0,0 +1,146 @@ +# vim: filetype=python +# Copyright 2019 Autodesk, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from SCons.Script import * + +import os, glob, re + +def find_tests_using_node(name, env): + TEST_GROUP = [] + l = glob.glob(os.path.join('testsuite', env['TEST_PATTERN'])) + + for test in l: + found = False + d = os.path.join(test, 'data') + if os.path.isdir(d): + for f in os.listdir(d): + path = os.path.join(d, f) + if os.path.isfile(path): + ext = os.path.splitext(f)[1] + expression = { + ".ass": "^[ \t]*%s[ \t]*\n[ \t]*{" % name, + ".py": "AiNode\([\"\']%s[\"\']\)" % name, + ".cpp": "AiNode\(\"%s\"\);" % name + }.get(ext, None) + + if expression: + with open(os.path.join(d, f), 'r') as file: + if re.search(expression, file.read(), re.MULTILINE): + found = True + break + if found: + TEST_GROUP.append(os.path.basename(test)) + + return TEST_GROUP + +## Finds a test group and returns a list of all tests included +def find_test_group(group, env): + + def find_test_group_in_file(group, file): + TEST_GROUP = set() + merge = False + found = False + + with open(file, 'r') as f: + for line in f.readlines(): + line = line.lstrip(' \t') + if line.startswith('#'): + # Skip comment lines + continue + (l, s, r) = line.partition(':') + if s == ':': + name = l.rstrip() + if name.endswith('+'): + merge = True + name = name[:-1] + else: + merge = False + if group == name: + # We found the test group + found = True + for t in Split(r): + if t.startswith('test_'): + TEST_GROUP.add(t) + else: + TEST_GROUP = TEST_GROUP.union(find_test_group(t, env)) + break + return (TEST_GROUP, found, merge) + + TEST_GROUP = set() + merge = False + found = False + + # The special "failed" group is expanded to the list of all failing tests + if group == 'failed': + for dir in glob.glob(os.path.join(env.Dir('.').abspath, 'test_*')): + file = os.path.join(dir, 'STATUS') + with open(str(file), 'r') as f: + value = f.readline().strip('\n') + if value != 'OK': + TEST_GROUP.add(os.path.basename(os.path.dirname(str(file)))) + # Special 'all' group is expanded to the whole testsuite, including the 'ignored' tests + elif group == 'all': + testlist = glob.glob(os.path.join('testsuite', env['TEST_PATTERN'])) + for name in testlist: + if os.path.exists(os.path.join(name, 'README')): + TEST_GROUP.add(os.path.basename(name)) + else: + # Search the user local file for this group (only if the local file exists) + if os.path.exists(os.path.join('testsuite', 'groups.local')): + (TEST_GROUP, found, merge) = find_test_group_in_file(group, os.path.join('testsuite', 'groups.local')) + + # If not found, then search the global test groups mapping file + if merge or not found: + (TEST_GROUP2, found, merge) = find_test_group_in_file(group, os.path.join('testsuite', 'groups')) + TEST_GROUP = TEST_GROUP.union(TEST_GROUP2) + + if merge or not found: + testlist = find_tests_using_node(group, env) + for name in testlist: + TEST_GROUP.add(os.path.basename(name)) + + return TEST_GROUP + +## Gets the next test name from the list of existing tests (assuming a 'test_0000' format) +def get_next_test_name(): + l = glob.glob(os.path.join("testsuite", 'test_[0-9][0-9][0-9][0-9]')) + l.sort() + result = int(os.path.basename(l[-1])[5:]) + 1 + return "%04d" % result + +# Get list of tests included in the given groups, or all tests if no group given +def get_test_list(groups, env, PATTERNS, TAGS): + tests = [] + if not groups: + pattern = env['TEST_PATTERN'] + PATTERNS.append(pattern) + for name in glob.glob(os.path.join('testsuite', pattern)): + tests.append(os.path.join(os.path.basename(name))) + else: + tags = groups.split(',') + for tag in tags: + if tag.startswith('test_'): + PATTERNS.append(tag) + for name in glob.glob(os.path.join('testsuite', tag)): + tests.append(os.path.join(os.path.basename(name))) + else: + TAGS.append(tag) + test_group = find_test_group(tag, env) + if len(test_group) == 0: + print "WARNING: No tests related to tag \"%s\"" % tag + else: + for test in test_group: + tests.append(test) + + return tests diff --git a/tools/utils/valgrind.py b/tools/utils/valgrind.py new file mode 100755 index 0000000000..218203c01e --- /dev/null +++ b/tools/utils/valgrind.py @@ -0,0 +1,257 @@ +# vim: filetype=python +# Copyright 2019 Autodesk, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os, shutil, string, platform, subprocess + +## Used for XTML/HTML parsing/modifying +from .contrib.beautiful_soup import BeautifulStoneSoup + +## Parses error records of a valgrind XML logfile +def vg_errors(file): + with open(file, 'r') as f: + vgXML = BeautifulStoneSoup(f) + vgErrorTags = vgXML.findAll('error') + return vgErrorTags + +## Counts the number of errors of a valgrind XML logfile +def vg_count_errors(file): + vgErrorTags = vg_errors(file) + nMemLeaksDL = 0 + nMemLeaksPL = 0 + nMemLeaksIL = 0 + nMemLeaksSR = 0 + nMemErrors = 0 + for vgErrorTag in vgErrorTags: + vgKind = str(vgErrorTag.kind.string) + if vgKind == "Leak_DefinitelyLost": + nMemLeaksDL += 1 + elif vgKind == "Leak_PossiblyLost": + nMemLeaksPL += 1 + elif vgKind == "Leak_IndirectlyLost": + nMemLeaksIL += 1 + elif vgKind == "Leak_StillReachable": + nMemLeaksSR += 1 + else: + nMemErrors += 1 + return nMemErrors, nMemLeaksDL, nMemLeaksPL, nMemLeaksIL, nMemLeaksSR + +## Generate a suppresion record for valgrind for a given error +def vg_supp_string(error): + error_stack = error.suppression.findAll('sframe') + supp_string = '{
       %s
       %s
    ' % (error.suppression.sname,error.suppression.skind) + for frame in error_stack: + supp_string += '   %s:%s
    ' % ( frame.fun != None and 'fun' or 'obj', frame.fun != None and frame.fun or frame.obj ) + supp_string += '}' + return supp_string + +## Create a HTML table of a kind of valgrind error +def vg_write_table(f, errors, title, tag): + if len(errors) > 0: + f.write('''
    '''%(title,tag)) + error_idx = 0 + for error in errors: + error_stack = error.stack.findAll('frame') + error_idx += 1 + f.write(''' + '''%(len(error_stack)+1,error_idx,error.xwhat != None and str(error.xwhat.text) or str(error.what))) + frame_idx = 0 + for frame in error_stack: + frame_idx += 1 + f.write(''' + + + + + + + %s + + ''' % ( + frame_idx == 1 and 'at' or 'by', + frame.ip == None and '????' or frame.ip, + frame.fn == None and '????' or frame.fn, + frame.file == None and '????' or os.path.basename(frame.file.string), + frame.line == None and '????' or frame.line, + frame.obj == None and '????' or os.path.basename(frame.obj.string), + frame_idx == 1 and (''%(len(error_stack),vg_supp_string(error))) or '' + )) + +# Writes a HTML report for a given valgrind XML logfile +def vg_write_report(f, vgf, use_valgrind): + if use_valgrind != 'False': + vgErrorTags = vg_errors(vgf) + MemErrors = [] + MemErrors_Bytes = 0 + MemErrors_Blocks = 0 + MemLeaksDL = [] + MemLeaksDL_Bytes = 0 + MemLeaksDL_Blocks = 0 + MemLeaksPL = [] + MemLeaksPL_Bytes = 0 + MemLeaksPL_Blocks = 0 + MemLeaksIL = [] + MemLeaksIL_Bytes = 0 + MemLeaksIL_Blocks = 0 + MemLeaksSR = [] + MemLeaksSR_Bytes = 0 + MemLeaksSR_Blocks = 0 + for vgErrorTag in vgErrorTags: + if str(vgErrorTag.kind.string) == "Leak_DefinitelyLost": + MemLeaksDL += [vgErrorTag] + MemLeaksDL_Bytes += int(vgErrorTag.xwhat.leakedbytes.string) + MemLeaksDL_Blocks += int(vgErrorTag.xwhat.leakedblocks.string) + elif str(vgErrorTag.kind.string) == "Leak_PossiblyLost": + MemLeaksPL += [vgErrorTag] + MemLeaksPL_Bytes += int(vgErrorTag.xwhat.leakedbytes.string) + MemLeaksPL_Blocks += int(vgErrorTag.xwhat.leakedblocks.string) + elif str(vgErrorTag.kind.string) == "Leak_IndirectlyLost": + MemLeaksIL += [vgErrorTag] + MemLeaksIL_Bytes += int(vgErrorTag.xwhat.leakedbytes.string) + MemLeaksIL_Blocks += int(vgErrorTag.xwhat.leakedblocks.string) + elif str(vgErrorTag.kind.string) == "Leak_StillReachable": + MemLeaksSR += [vgErrorTag] + MemLeaksSR_Bytes += int(vgErrorTag.xwhat.leakedbytes.string) + MemLeaksSR_Blocks += int(vgErrorTag.xwhat.leakedblocks.string) + else: + MemErrors += [vgErrorTag] + MemErrors_Bytes += 0 + MemErrors_Blocks += 0 + + if use_valgrind == 'Full': + f.write(''' +

    Valgrind report

    + +
     %s 
     %d  %s 
    + +  %s  + + + +  %s  + + + +  %s  + + + +  %s:%s  + + + +  %s  + +
    %s
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
     MEM. ERRORS/CORRUPTIONS  %d  %d  errors/corruptions 
     MAJOR MEM. LEAKS  %d  %d  definitely lost:  %d bytes in %d blocks
     %d  possibly lost:  %d bytes in %d blocks
     MINOR MEM. LEAKS  %d  %d  indirectly lost:  %d bytes in %d blocks
     %d  still reachable:  %d bytes in %d blocks
    + +
    + ''' % ( + len(MemErrors)>0 and '#DD7E7E' or '#ececec',len(MemErrors), + len(MemErrors), + len(MemLeaksDL)+len(MemLeaksPL)>0 and '#ffa0a0' or '#ececec',len(MemLeaksDL)+len(MemLeaksPL), + len(MemLeaksDL),MemLeaksDL_Bytes,MemLeaksDL_Blocks, + len(MemLeaksPL),MemLeaksPL_Bytes,MemLeaksPL_Blocks, + len(MemLeaksIL)+len(MemLeaksSR)>0 and '#ffc2c2' or '#ececec',len(MemLeaksIL)+len(MemLeaksSR), + len(MemLeaksIL),MemLeaksIL_Bytes,MemLeaksIL_Blocks, + len(MemLeaksSR),MemLeaksSR_Bytes,MemLeaksSR_Blocks + ) + ) + else: + f.write(''' +

    Valgrind report

    + + + + + + + + + + + + + + + + + + + + +
     MEM. ERRORS/CORRUPTIONS  %d  errors/corruptions 
     MAJOR MEM. LEAKS  %d  definitely lost:  %d bytes in %d blocks
    +
    +
    + ''' % ( + len(MemErrors)>0 and '#DD7E7E' or '#ececec', + len(MemErrors), + len(MemLeaksDL)>0 and '#ffa0a0' or '#ececec', + len(MemLeaksDL), + MemLeaksDL_Bytes, + MemLeaksDL_Blocks + ) + ) + f.write('''''') + vg_write_table(f, MemErrors, "Memory Errors/Corruptions", "memerrors") + vg_write_table(f, MemLeaksDL, "Memory Definitely Lost" , "memleaksDL") + if use_valgrind == 'Full': + vg_write_table(f, MemLeaksPL, "Memory Possibly Lost" , "memleaksPL") + vg_write_table(f, MemLeaksIL, "Memory Indirectly Lost" , "memleaksIL") + vg_write_table(f, MemLeaksSR, "Memory Still Reachable" , "memleaksSR") + f.write('''

    ''') diff --git a/tools/utils/version.py b/tools/utils/version.py new file mode 100755 index 0000000000..3ac163a85f --- /dev/null +++ b/tools/utils/version.py @@ -0,0 +1,57 @@ +# vim: filetype=python +# Copyright 2019 Autodesk, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import operator + +class Version: + + # Constructor + def __init__(self, v, t = None, s = '.'): + self.__v = [] # Version number X.Y.Z... as a list [X,Y,Z,...] + self.__t = t # Version tag. As in X.Y.Z.tag or X.Y.Z-tag + self.__s = s # Separator between Version number and Version tag + if isinstance(v, Version): + self.__v = v + elif (type(v) == list) and ([type(x) for x in v] == [int] * len(v)): + self.__v = v + elif (type(v) == str): + try: self.__v = [int(x) for x in v.split('.')] + except ValueError: pass + + # printable representation + def __repr__(self): + return '.'.join([('%u' % x) for x in self.__v]) + (self.__t and (self.__s + self.__t) or '') + + # nesting degree of the version + # 4 = 1, 4.0 = 2, 4.0.0 = 3, etc. + def __len__(self): return len(self.__v) + + # [] operators for set and get + def __getitem__(self, i): return self.__v[i] + def __setitem__(self, i, e): self.__v[i] = e + + # this is a private method used by the comparison operators + def __compare(self, other, func): + n = max(len(self), len(other)) + L = self.__v + [0] * (n - len(self) ) + R = other.__v + [0] * (n - len(other)) + return func(L, R) + + # Comparison operators + def __lt__(self, other): return self.__compare(other, operator.lt) + def __le__(self, other): return self.__compare(other, operator.le) + def __eq__(self, other): return self.__compare(other, operator.eq) + def __ne__(self, other): return self.__compare(other, operator.ne) + def __ge__(self, other): return self.__compare(other, operator.ge) + def __gt__(self, other): return self.__compare(other, operator.gt) diff --git a/translator/SConscript b/translator/SConscript new file mode 100755 index 0000000000..7da5810c7c --- /dev/null +++ b/translator/SConscript @@ -0,0 +1,60 @@ +# vim: filetype=python +# Copyright 2019 Autodesk, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +## load our own python modules +from utils import system +from utils.build_tools import find_files_recursive + +import os + +# import build env +Import('env') +myenv = env.Clone() + +# Automatically add all source and include files found in the source path +src_base_dir = os.path.join(myenv['ROOT_DIR'], 'translator') +source_files = find_files_recursive(src_base_dir, ['.c', '.cpp']) + +# Compiler flags +if system.os != 'windows': + myenv.Append(CXXFLAGS = Split('-fPIC -Wno-deprecated-register')) + +myenv.Append(CPPPATH = ['.']) + +myenv.Append(LIBS = ['ai']) + +usd_deps = [] + +if myenv['USD_BUILD_MODE'] == 'monolithic': + usd_deps = [ + myenv['USD_MONOLITHIC_LIBRARY'], + ] +elif myenv['USD_BUILD_MODE'] == 'shared_libs': + usd_deps = [ + 'sdf', + 'tf', + 'usd', + 'ar', + 'usdGeom', + 'usdShade', + 'vt', + 'usdLux', + ] + +myenv.Append(LIBS = usd_deps) + +# Build shared library for the Alembic procedural +USD_TRANSLATOR = myenv.StaticLibrary('usd_translator', source_files) + +Return('USD_TRANSLATOR') diff --git a/translator/reader/prim_reader.cpp b/translator/reader/prim_reader.cpp new file mode 100755 index 0000000000..9e59228f96 --- /dev/null +++ b/translator/reader/prim_reader.cpp @@ -0,0 +1,297 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include +#include +#include +#include +#include + +#include +#include "prim_reader.h" + +//-************************************************************************* + +PXR_NAMESPACE_USING_DIRECTIVE + +// Unsupported node types should dump a warning when being converted +void UsdArnoldReadUnsupported::read(const UsdPrim &prim, UsdArnoldReader &reader, bool create, bool convert) +{ + AiMsgWarning( + "UsdArnoldReader : %s primitives not supported, cannot read %s", _type.c_str(), prim.GetName().GetText()); +} + +/** + * Read all the arnold-specific attributes that were saved in this USD + *primitive. Arnold attributes are prefixed with the namespace 'arnold:' We will + *strip this prefix, look for the corresponding arnold parameter, and convert it + *based on its type + **/ +void UsdArnoldPrimReader::readArnoldParameters( + const UsdPrim &prim, UsdArnoldReader &reader, AtNode *node, const TimeSettings &time) +{ + const AtNodeEntry *nodeEntry = AiNodeGetNodeEntry(node); + if (nodeEntry == NULL) { + return; // shouldn't happen + } + + float frame = time.frame; + UsdAttributeVector attributes = prim.GetAttributes(); + + // We currently support the following namespaces for arnold input attributes + TfToken arnoldToken("arnold"); + TfToken inputToken("input"); + TfToken inputsToken("inputs"); + + for (size_t i = 0; i < attributes.size(); ++i) { + UsdAttribute &attr = attributes[i]; + + TfToken attrNamespace = attr.GetNamespace(); + + if (attrNamespace != arnoldToken && + attrNamespace != inputToken && + attrNamespace != inputsToken) { // only deal with attributes of the desired scope + continue; + } + + std::string arnoldAttr = attr.GetBaseName().GetString(); + const AtParamEntry *paramEntry = AiNodeEntryLookUpParameter(nodeEntry, AtString(arnoldAttr.c_str())); + if (paramEntry == NULL) { + AiMsgWarning( + "USD arnold attribute %s not recognized in %s", arnoldAttr.c_str(), AiNodeEntryGetName(nodeEntry)); + continue; + } + uint8_t paramType = AiParamGetType(paramEntry); + + VtValue vtValue; + attr.Get(&vtValue, frame); + + if (paramType == AI_TYPE_ARRAY) { + // Let's separate the code for arrays as it's more complicated + const AtParamValue *defaultValue = AiParamGetDefault(paramEntry); + // Getting the default array, and checking its type + int arrayType = (defaultValue) ? AiArrayGetType(defaultValue->ARRAY()) : AI_TYPE_NONE; + + if (arrayType == AI_TYPE_NONE) { + // No default value found in the AtParamEntry default + // definition, let's check the USD value instead + if (vtValue.IsHolding >()) + arrayType = AI_TYPE_BYTE; + else if (vtValue.IsHolding >()) + arrayType = AI_TYPE_INT; + else if (vtValue.IsHolding >()) + arrayType = AI_TYPE_UINT; + else if (vtValue.IsHolding >()) + arrayType = AI_TYPE_BOOLEAN; + else if (vtValue.IsHolding >()) + arrayType = AI_TYPE_FLOAT; + else if (vtValue.IsHolding >()) + arrayType = AI_TYPE_VECTOR; + else if (vtValue.IsHolding >()) + arrayType = AI_TYPE_RGBA; + else if (vtValue.IsHolding >()) + arrayType = AI_TYPE_VECTOR2; + else if (vtValue.IsHolding >()) + arrayType = AI_TYPE_STRING; + else if (vtValue.IsHolding >()) + arrayType = AI_TYPE_MATRIX; + } + + // The default array has a type, let's do the conversion based on it + switch (arrayType) { + case AI_TYPE_BYTE: + exportArray(attr, node, arnoldAttr.c_str(), time); + break; + case AI_TYPE_INT: + exportArray(attr, node, arnoldAttr.c_str(), time); + break; + case AI_TYPE_UINT: + exportArray(attr, node, arnoldAttr.c_str(), time); + break; + case AI_TYPE_BOOLEAN: + exportArray(attr, node, arnoldAttr.c_str(), time); + break; + case AI_TYPE_FLOAT: + exportArray(attr, node, arnoldAttr.c_str(), time); + break; + { + case AI_TYPE_VECTOR: + case AI_TYPE_RGB: + exportArray(attr, node, arnoldAttr.c_str(), time); + break; + } + { + case AI_TYPE_RGBA: + exportArray(attr, node, arnoldAttr.c_str(), time); + break; + } + { + case AI_TYPE_VECTOR2: + exportArray(attr, node, arnoldAttr.c_str(), time); + break; + } + { + // FIXME: ensure enum is working here + case AI_TYPE_ENUM: + case AI_TYPE_STRING: + exportArray(attr, node, arnoldAttr.c_str(), time); + break; + } + { + case AI_TYPE_MATRIX: + VtArray array; + attr.Get(&array, frame); + // special case for matrices. They're single + // precision in arnold but double precision in USD, + // and there is no copy from one to the other. + std::vector arnoldVec(array.size()); + for (size_t v = 0; v < arnoldVec.size(); ++v) { + AtMatrix &aiMat = arnoldVec[v]; + const double *matArray = array[v].GetArray(); + for (unsigned int i = 0; i < 4; ++i) + for (unsigned int j = 0; j < 4; ++j) + aiMat[i][j] = matArray[4 * i + j]; + } + AiNodeSetArray( + node, arnoldAttr.c_str(), + AiArrayConvert(array.size(), 1, AI_TYPE_MATRIX, &arnoldVec[0])); + break; + } + { + case AI_TYPE_NODE: + VtArray array; + attr.Get(&array, frame); + std::vector arnoldVec(array.size(), nullptr); + for (size_t v = 0; v < arnoldVec.size(); ++v) { + std::string nodeName = array[v]; + if (nodeName.empty()) { + continue; + } + nodeName = std::string("/") + nodeName; + SdfPath targetPath(nodeName); + + UsdPrim targetPrim = reader.getStage()->GetPrimAtPath(targetPath); + // export this node + if (targetPrim) { + reader.readPrimitive(targetPrim, true, false); + } + // the above call should have created the shader already + arnoldVec[v] = + AiNodeLookUpByName(targetPrim.GetPath().GetText(), reader.getProceduralParent()); + } + AiNodeSetArray( + node, arnoldAttr.c_str(), AiArrayConvert(array.size(), 1, AI_TYPE_NODE, &arnoldVec[0])); + break; + } + default: + break; + } + } else { + // Simple parameters (not-an-array) + switch (paramType) { + case AI_TYPE_BYTE: + AiNodeSetByte(node, arnoldAttr.c_str(), vtValue.Get()); + break; + case AI_TYPE_INT: + AiNodeSetInt(node, arnoldAttr.c_str(), vtValue.Get()); + break; + case AI_TYPE_UINT: + AiNodeSetUInt(node, arnoldAttr.c_str(), vtValue.Get()); + break; + case AI_TYPE_BOOLEAN: + AiNodeSetBool(node, arnoldAttr.c_str(), vtValue.Get()); + break; + case AI_TYPE_FLOAT: + AiNodeSetFlt(node, arnoldAttr.c_str(), vtValue.Get()); + break; + { + case AI_TYPE_VECTOR: + case AI_TYPE_RGB: + GfVec3f vec = vtValue.Get(); + AiNodeSetRGB(node, arnoldAttr.c_str(), vec[0], vec[1], vec[2]); + break; + } + { + case AI_TYPE_RGBA: + GfVec4f vec = vtValue.Get(); + AiNodeSetRGBA(node, arnoldAttr.c_str(), vec[0], vec[1], vec[2], vec[3]); + break; + } + { + case AI_TYPE_VECTOR2: + GfVec2f vec = vtValue.Get(); + AiNodeSetVec2(node, arnoldAttr.c_str(), vec[0], vec[1]); + break; + } + { + // FIXME: ensure enum is working here + case AI_TYPE_ENUM: + case AI_TYPE_STRING: + std::string str = vtValue.Get(); + AiNodeSetStr(node, arnoldAttr.c_str(), str.c_str()); + break; + } + { + case AI_TYPE_MATRIX: + GfMatrix4d usdMat = vtValue.Get(); + AtMatrix aiMat; + const double *array = usdMat.GetArray(); + for (unsigned int i = 0; i < 4; ++i) + for (unsigned int j = 0; j < 4; ++j) + aiMat[i][j] = array[4 * i + j]; + AiNodeSetMatrix(node, arnoldAttr.c_str(), aiMat); + break; + } + { + // node attributes are expected as strings + case AI_TYPE_NODE: + std::string nodeName = vtValue.Get(); + if (!nodeName.empty()) { + nodeName = std::string("/") + nodeName; + UsdPrim targetPrim = reader.getStage()->GetPrimAtPath(SdfPath(nodeName)); + // export this node + if (targetPrim && targetPrim.IsActive()) { + reader.readPrimitive(targetPrim, true, false); + } + // the above call should have created the shader already + AiNodeSetPtr( + node, arnoldAttr.c_str(), + (AtNode *)AiNodeLookUpByName( + targetPrim.GetPath().GetText(), reader.getProceduralParent())); + } + break; + } + default: + break; + } + // check if there are connections to this attribute + if (attr.HasAuthoredConnections()) { + SdfPathVector targets; + attr.GetConnections(&targets); + // arnold can only have a single connection to an attribute + if (!targets.empty()) { + UsdPrim targetPrim = reader.getStage()->GetPrimAtPath(targets[0]); + if (targetPrim) { + reader.readPrimitive(targetPrim, true, false); + // the above call should have created the shader already + AtNode *target = + AiNodeLookUpByName(targetPrim.GetPath().GetText(), reader.getProceduralParent()); + if (target) { + AiNodeLink(target, arnoldAttr.c_str(), node); + } + } + } + } + } + } +} diff --git a/translator/reader/prim_reader.h b/translator/reader/prim_reader.h new file mode 100755 index 0000000000..1c0dbb2f1b --- /dev/null +++ b/translator/reader/prim_reader.h @@ -0,0 +1,58 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "reader.h" +#include "utils.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +/** + * Base Class for a UsdPrim read. This class is in charge of converting a USD + *primitive to Arnold + * + **/ +class UsdArnoldPrimReader { +public: + UsdArnoldPrimReader() {} + virtual ~UsdArnoldPrimReader() {} + + virtual void read(const UsdPrim &prim, UsdArnoldReader &reader, bool create, bool convert) = 0; + +protected: + void readArnoldParameters( + const UsdPrim &prim, UsdArnoldReader &reader, AtNode *node, const TimeSettings &time); +}; + +class UsdArnoldReadUnsupported : public UsdArnoldPrimReader { +public: + UsdArnoldReadUnsupported(const std::string &type) : UsdArnoldPrimReader(), _type(type) {} + void read(const UsdPrim &prim, UsdArnoldReader &reader, bool create, bool convert) override; + +private: + std::string _type; +}; + +#define REGISTER_PRIM_READER(name) \ + class name : public UsdArnoldPrimReader { \ + public: \ + void read(const UsdPrim &prim, UsdArnoldReader &reader, bool create, bool convert) override; \ + }; diff --git a/translator/reader/read_arnold_type.cpp b/translator/reader/read_arnold_type.cpp new file mode 100755 index 0000000000..84a547c218 --- /dev/null +++ b/translator/reader/read_arnold_type.cpp @@ -0,0 +1,51 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "read_arnold_type.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include "utils.h" + +//-************************************************************************* + +PXR_NAMESPACE_USING_DIRECTIVE + +/** Export USD native shaders to Arnold + * + **/ +void UsdArnoldReadArnoldType::read(const UsdPrim &prim, UsdArnoldReader &reader, bool create, bool convert) +{ + AtNode *node = getNodeToConvert(reader, _entryName.c_str(), prim.GetPath().GetText(), create, convert); + if (node == nullptr) { + return; + } + + if (convert) { + const TimeSettings &time = reader.getTimeSettings(); + + std::string objType = prim.GetTypeName().GetText(); + // The only job here is to look for arnold specific attributes and + // convert them. If this primitive if a UsdShader "Shader" type, we're + // looking for an attribute namespace "input", otherwise this is just an + // arnold typed schema and we want the "arnold" namespace. + readArnoldParameters(prim, reader, node, time); + } +} \ No newline at end of file diff --git a/translator/reader/read_arnold_type.h b/translator/reader/read_arnold_type.h new file mode 100755 index 0000000000..6e5f9ceee0 --- /dev/null +++ b/translator/reader/read_arnold_type.h @@ -0,0 +1,38 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include +#include +#include + +#include + +#include "prim_reader.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +// Register readers for the USD builtin types +class UsdArnoldReadArnoldType : public UsdArnoldPrimReader { +public: + UsdArnoldReadArnoldType(const std::string &entryName, const std::string &entryTypeName) + : UsdArnoldPrimReader(), _entryName(entryName), _entryTypeName(entryTypeName) + { + } + void read(const UsdPrim &prim, UsdArnoldReader &reader, bool create, bool convert) override; + +private: + std::string _entryName; + std::string _entryTypeName; +}; diff --git a/translator/reader/read_geometry.cpp b/translator/reader/read_geometry.cpp new file mode 100755 index 0000000000..34bbea7ccf --- /dev/null +++ b/translator/reader/read_geometry.cpp @@ -0,0 +1,311 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "read_geometry.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "utils.h" +//-************************************************************************* + +PXR_NAMESPACE_USING_DIRECTIVE + +/** Exporting a USD Mesh description to Arnold + * TODO: - what to do with UVs ? + **/ +void UsdArnoldReadMesh::read(const UsdPrim &prim, UsdArnoldReader &reader, bool create, bool convert) +{ + AtNode *node = getNodeToConvert(reader, "polymesh", prim.GetPath().GetText(), create, convert); + if (node == nullptr) + return; + + AiNodeSetBool(node, "smoothing", true); + const TimeSettings &time = reader.getTimeSettings(); + float frame = time.frame; + + // Get mesh. + UsdGeomMesh mesh(prim); + + MeshOrientation mesh_orientation; + // Get orientation. If Left-handed, we will need to invert the vertex + // indices + { + TfToken orientation_token; + if (mesh.GetOrientationAttr().Get(&orientation_token)) { + if (orientation_token == UsdGeomTokens->leftHanded) { + mesh_orientation.reverse = true; + mesh.GetFaceVertexCountsAttr().Get(&mesh_orientation.nsides_array, frame); + } + } + } + exportArray(mesh.GetFaceVertexCountsAttr(), node, "nsides", time); + + if (!mesh_orientation.reverse) { + // Basic right-handed orientation, no need to do anything special here + exportArray(mesh.GetFaceVertexIndicesAttr(), node, "vidxs", time); + } else { + // We can't call exportArray here because the orientation requires to + // reverse face attributes. So we're duplicating the function here. + VtIntArray array; + mesh.GetFaceVertexIndicesAttr().Get(&array, frame); + size_t size = array.size(); + if (size > 0) { + mesh_orientation.orient_face_index_attribute(array); + + // Need to convert the data from int to unsigned int + std::vector arnold_vec(array.begin(), array.end()); + AiNodeSetArray(node, "vidxs", AiArrayConvert(size, 1, AI_TYPE_UINT, arnold_vec.data())); + } else + AiNodeResetParameter(node, "vidxs"); + } + + // Vertex positions + exportArray(mesh.GetPointsAttr(), node, "vlist", time); + + VtValue sidedness; + if (mesh.GetDoubleSidedAttr().Get(&sidedness)) + AiNodeSetByte(node, "sidedness", sidedness.Get() ? AI_RAY_ALL : 0); + + TfToken subdiv; + mesh.GetSubdivisionSchemeAttr().Get(&subdiv); + if (subdiv == UsdGeomTokens->none) + AiNodeSetStr(node, "subdiv_type", "none"); + else if (subdiv == UsdGeomTokens->catmullClark) + AiNodeSetStr(node, "subdiv_type", "catclark"); + else if (subdiv == UsdGeomTokens->bilinear) + AiNodeSetStr(node, "subdiv_type", "linear"); + else + AiMsgWarning( + "[usd] %s subdivision scheme not supported for mesh on path %s", subdiv.GetString().c_str(), + mesh.GetPath().GetString().c_str()); + + exportMatrix(prim, node, time); + + exportPrimvars(prim, node, time, &mesh_orientation); + exportMaterialBinding(prim, node, reader); + + readArnoldParameters(prim, reader, node, time); +} + +void UsdArnoldReadCurves::read(const UsdPrim &prim, UsdArnoldReader &reader, bool create, bool convert) +{ + AtNode *node = getNodeToConvert(reader, "curves", prim.GetPath().GetText(), create, convert); + if (node == nullptr) + return; + + const TimeSettings &time = reader.getTimeSettings(); + float frame = time.frame; + + int basis = 3; + if (prim.IsA()) { + // TODO: use a scope_pointer for curves and basisCurves. + UsdGeomBasisCurves basisCurves(prim); + TfToken curveType; + basisCurves.GetTypeAttr().Get(&curveType, frame); + if (curveType == UsdGeomTokens->cubic) { + TfToken basisType; + basisCurves.GetBasisAttr().Get(&basisType, frame); + + if (basisType == UsdGeomTokens->bezier) + basis = 0; + else if (basisType == UsdGeomTokens->bspline) + basis = 1; + else if (basisType == UsdGeomTokens->catmullRom) + basis = 2; + } + } + AiNodeSetInt(node, "basis", basis); + + UsdGeomCurves curves(prim); + // CV counts per curve + exportArray(curves.GetCurveVertexCountsAttr(), node, "num_points", time); + // CVs positions + exportArray(curves.GetPointsAttr(), node, "points", time); + // Widths + exportArray(curves.GetWidthsAttr(), node, "radius", time); + + exportMatrix(prim, node, time); + exportPrimvars(prim, node, time); + exportMaterialBinding(prim, node, reader); + + readArnoldParameters(prim, reader, node, time); +} + +void UsdArnoldReadPoints::read(const UsdPrim &prim, UsdArnoldReader &reader, bool create, bool convert) +{ + AtNode *node = getNodeToConvert(reader, "points", prim.GetPath().GetText(), create, convert); + if (node == nullptr) + return; + + UsdGeomPoints points(prim); + const TimeSettings &time = reader.getTimeSettings(); + float frame = time.frame; + + // Points positions + exportArray(points.GetPointsAttr(), node, "points", time); + // Points radius + exportArray(points.GetWidthsAttr(), node, "radius", time); + + exportMatrix(prim, node, time); + + exportPrimvars(prim, node, time); + exportMaterialBinding(prim, node, reader); + readArnoldParameters(prim, reader, node, time); +} + +/** + * Convert the basic USD shapes (cube, sphere, cylinder, cone,...) + * to Arnold. There are 2 main differences so far : + * - capsules don't exist in arnold + * - cylinders are different (one is closed the other isn't) + **/ +void UsdArnoldReadCube::read(const UsdPrim &prim, UsdArnoldReader &reader, bool create, bool convert) +{ + AtNode *node = getNodeToConvert(reader, "box", prim.GetPath().GetText(), create, convert); + if (node == nullptr) + return; + + UsdGeomCube cube(prim); + const TimeSettings &time = reader.getTimeSettings(); + float frame = time.frame; + + VtValue size_attr; + if (cube.GetSizeAttr().Get(&size_attr)) { + float size_value = (float)size_attr.Get(); + AiNodeSetVec(node, "min", -size_value / 2.f, -size_value / 2.f, -size_value / 2.f); + AiNodeSetVec(node, "max", size_value / 2.f, size_value / 2.f, size_value / 2.f); + } + + exportMatrix(prim, node, time); + exportPrimvars(prim, node, time); + exportMaterialBinding(prim, node, reader); + readArnoldParameters(prim, reader, node, time); +} +void UsdArnoldReadSphere::read(const UsdPrim &prim, UsdArnoldReader &reader, bool create, bool convert) +{ + AtNode *node = getNodeToConvert(reader, "sphere", prim.GetPath().GetText(), create, convert); + if (node == nullptr) + return; + + UsdGeomSphere sphere(prim); + const TimeSettings &time = reader.getTimeSettings(); + float frame = time.frame; + + VtValue radius_attr; + if (sphere.GetRadiusAttr().Get(&radius_attr)) + AiNodeSetFlt(node, "radius", (float)radius_attr.Get()); + + exportMatrix(prim, node, time); + exportPrimvars(prim, node, time); + exportMaterialBinding(prim, node, reader); + readArnoldParameters(prim, reader, node, time); +} + +// Conversion code that is common to cylinder, cone and capsule +template +void exportCylindricalShape(const UsdPrim &prim, AtNode *node, const char *radius_name) +{ + T geom(prim); + + VtValue radius_attr; + if (geom.GetRadiusAttr().Get(&radius_attr)) + AiNodeSetFlt(node, radius_name, (float)radius_attr.Get()); + + float height = 1.f; + VtValue height_attr; + if (geom.GetHeightAttr().Get(&height_attr)) + height = (float)height_attr.Get(); + + height /= 2.f; + + TfToken axis; + geom.GetAxisAttr().Get(&axis); + AtVector bottom(0.f, 0.f, 0.f); + AtVector top(0.f, 0.f, 0.f); + + if (axis == UsdGeomTokens->x) { + bottom.x = -height; + top.x = height; + } else if (axis == UsdGeomTokens->y) { + bottom.y = -height; + top.y = height; + } else // UsdGeomTokens->z or unknown + { + bottom.z = -height; + top.z = height; + } + AiNodeSetVec(node, "bottom", bottom.x, bottom.y, bottom.z); + AiNodeSetVec(node, "top", top.x, top.y, top.z); +} + +void UsdArnoldReadCylinder::read(const UsdPrim &prim, UsdArnoldReader &reader, bool create, bool convert) +{ + AtNode *node = getNodeToConvert(reader, "cylinder", prim.GetPath().GetText(), create, convert); + if (node == nullptr) + return; + + exportCylindricalShape(prim, node, "radius"); + const TimeSettings &time = reader.getTimeSettings(); + float frame = time.frame; + + exportMatrix(prim, node, time); + exportPrimvars(prim, node, time); + exportMaterialBinding(prim, node, reader); + readArnoldParameters(prim, reader, node, time); +} + +void UsdArnoldReadCone::read(const UsdPrim &prim, UsdArnoldReader &reader, bool create, bool convert) +{ + AtNode *node = getNodeToConvert(reader, "cone", prim.GetPath().GetText(), create, convert); + if (node == nullptr) + return; + + exportCylindricalShape(prim, node, "bottom_radius"); + + const TimeSettings &time = reader.getTimeSettings(); + exportMatrix(prim, node, time); + exportPrimvars(prim, node, time); + exportMaterialBinding(prim, node, reader); + readArnoldParameters(prim, reader, node, time); +} + +// Note that we don't have capsule shapes in Arnold. Do we want to make a +// special case, and combine cylinders with spheres, or is it enough for now ? + +void UsdArnoldReadCapsule::read(const UsdPrim &prim, UsdArnoldReader &reader, bool create, bool convert) +{ + AtNode *node = getNodeToConvert(reader, "cylinder", prim.GetPath().GetText(), create, convert); + if (node == nullptr) + return; + + exportCylindricalShape(prim, node, "radius"); + const TimeSettings &time = reader.getTimeSettings(); + exportMatrix(prim, node, time); + exportPrimvars(prim, node, time); + exportMaterialBinding(prim, node, reader); + readArnoldParameters(prim, reader, node, time); +} diff --git a/translator/reader/read_geometry.h b/translator/reader/read_geometry.h new file mode 100755 index 0000000000..248e8f440c --- /dev/null +++ b/translator/reader/read_geometry.h @@ -0,0 +1,43 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include + +#include + +#include +#include +#include + +#include "prim_reader.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +// Register readers for the USD builtin Geometries + +REGISTER_PRIM_READER(UsdArnoldReadMesh); +REGISTER_PRIM_READER(UsdArnoldReadCurves); +REGISTER_PRIM_READER(UsdArnoldReadPoints); +REGISTER_PRIM_READER(UsdArnoldReadCube); +REGISTER_PRIM_READER(UsdArnoldReadSphere); +REGISTER_PRIM_READER(UsdArnoldReadCylinder); +REGISTER_PRIM_READER(UsdArnoldReadCone); +REGISTER_PRIM_READER(UsdArnoldReadCapsule); + +/* + +// USD builtin Shaders +REGISTER_PRIM_READER(UsdArnoldReadShader); +*/ diff --git a/translator/reader/read_light.cpp b/translator/reader/read_light.cpp new file mode 100755 index 0000000000..0efdc51d9e --- /dev/null +++ b/translator/reader/read_light.cpp @@ -0,0 +1,308 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "read_light.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +//-************************************************************************* + +PXR_NAMESPACE_USING_DIRECTIVE + +static void exportLightCommon(const UsdLuxLight &light, AtNode *node) +{ + // This function is computing intensity, color, and eventually color + // temperature. Another solution could be to export separately these + // parameters, but it seems simpler to do this for now + GfVec3f color = light.ComputeBaseEmission(); + AiNodeSetRGB(node, "color", color[0], color[1], color[2]); + AiNodeSetFlt(node, "intensity", 1.f); + AiNodeSetFlt(node, "exposure", 0.f); + + VtValue diffuse_attr; + if (light.GetDiffuseAttr().Get(&diffuse_attr)) { + AiNodeSetFlt(node, "diffuse", diffuse_attr.Get()); + } + VtValue specular_attr; + if (light.GetSpecularAttr().Get(&specular_attr)) { + AiNodeSetFlt(node, "specular", specular_attr.Get()); + } + + /* + This is preventing distant lights from working properly, so we should only + do it where it makes sense VtValue normalize_attr; + if(light.GetNormalizeAttr().Get(&normalize_attr)) + AiNodeSetBool(node, "normalize", normalize_attr.Get()); + */ +} + +void UsdArnoldReadDistantLight::read(const UsdPrim &prim, UsdArnoldReader &reader, bool create, bool convert) +{ + AtNode *node = getNodeToConvert(reader, "distant_light", prim.GetPath().GetText(), create, convert); + if (node == nullptr) { + return; + } + + UsdLuxDistantLight light(prim); + + float angle = 0.52f; + VtValue angle_attr; + if (light.GetAngleAttr().Get(&angle_attr)) { + AiNodeSetFlt(node, "angle", angle_attr.Get()); + } + + const TimeSettings &time = reader.getTimeSettings(); + + exportLightCommon(light, node); + exportMatrix(prim, node, time); + readArnoldParameters(prim, reader, node, time); +} + +void UsdArnoldReadDomeLight::read(const UsdPrim &prim, UsdArnoldReader &reader, bool create, bool convert) +{ + AtNode *node = getNodeToConvert(reader, "skydome_light", prim.GetPath().GetText(), create, convert); + if (node == nullptr) { + return; + } + + UsdLuxDomeLight light(prim); + + // TODO : portal + exportLightCommon(light, node); + const TimeSettings &time = reader.getTimeSettings(); + + SdfAssetPath texture_path; + if (light.GetTextureFileAttr().Get(&texture_path)) { + VtValue filename_vt(texture_path.GetResolvedPath()); + std::string filename = filename_vt.Get(); + if (!filename.empty()) { + // there's a texture filename, so we need to connect it to the color + std::string imageName(prim.GetPath().GetText()); + imageName += "/texture_file"; + AtNode *image = reader.createArnoldNode("image", imageName.c_str()); + + AiNodeSetStr(image, "filename", filename.c_str()); + AiNodeLink(image, "color", node); + + // now we need to export the intensity and exposure manually, + // because we have overridden the color + float intensity = 1.f; + light.GetIntensityAttr().Get(&intensity); + AiNodeSetFlt(node, "intensity", intensity); + float exposure = 0.f; + light.GetExposureAttr().Get(&exposure); + AiNodeSetFlt(node, "exposure", exposure); + } + } + TfToken format; + if (light.GetTextureFormatAttr().Get(&format)) { + if (format == UsdLuxTokens->latlong) { + AiNodeSetStr(node, "format", AtString("latlong")); + } else if (format == UsdLuxTokens->mirroredBall) { + AiNodeSetStr(node, "format", AtString("mirrored_ball")); + } else if (format == UsdLuxTokens->angular) { + AiNodeSetStr(node, "format", AtString("angular")); + } + } + AiNodeSetFlt(node, "camera", 0.f); + + exportMatrix(prim, node, time); + readArnoldParameters(prim, reader, node, time); +} + +void UsdArnoldReadDiskLight::read(const UsdPrim &prim, UsdArnoldReader &reader, bool create, bool convert) +{ + AtNode *node = getNodeToConvert(reader, "disk_light", prim.GetPath().GetText(), create, convert); + if (node == nullptr) { + return; + } + + UsdLuxDiskLight light(prim); + + const TimeSettings &time = reader.getTimeSettings(); + + exportLightCommon(light, node); + + VtValue radius_attr; + if (light.GetRadiusAttr().Get(&radius_attr)) { + AiNodeSetFlt(node, "radius", radius_attr.Get()); + } + + VtValue normalize_attr; + if (light.GetNormalizeAttr().Get(&normalize_attr)) { + AiNodeSetBool(node, "normalize", normalize_attr.Get()); + } + + exportMatrix(prim, node, time); + readArnoldParameters(prim, reader, node, time); +} + +// Sphere lights get exported to arnold as a point light with a radius +void UsdArnoldReadSphereLight::read(const UsdPrim &prim, UsdArnoldReader &reader, bool create, bool convert) +{ + AtNode *node = getNodeToConvert(reader, "point_light", prim.GetPath().GetText(), create, convert); + if (node == nullptr) { + return; + } + + UsdLuxSphereLight light(prim); + exportLightCommon(light, node); + + bool treatAsPoint = false; + if (light.GetTreatAsPointAttr().Get(&treatAsPoint) && (!treatAsPoint)) { + VtValue radiusAttr; + if (light.GetRadiusAttr().Get(&radiusAttr)) { + AiNodeSetFlt(node, "radius", radiusAttr.Get()); + } + + VtValue normalizeAttr; + if (light.GetNormalizeAttr().Get(&normalizeAttr)) { + AiNodeSetBool(node, "normalize", normalizeAttr.Get()); + } + } + + const TimeSettings &time = reader.getTimeSettings(); + + exportMatrix(prim, node, time); + readArnoldParameters(prim, reader, node, time); +} + +void UsdArnoldReadRectLight::read(const UsdPrim &prim, UsdArnoldReader &reader, bool create, bool convert) +{ + AtNode *node = getNodeToConvert(reader, "quad_light", prim.GetPath().GetText(), create, convert); + if (node == nullptr) { + return; + } + + const TimeSettings &time = reader.getTimeSettings(); + + UsdLuxRectLight light(prim); + exportLightCommon(light, node); + + float width = 1.f; + float height = 1.f; + + light.GetWidthAttr().Get(&width); + light.GetHeightAttr().Get(&height); + + width /= 2.f; + height /= 2.f; + + AtVector vertices[4]; + vertices[3] = AtVector(width, height, 0); + vertices[0] = AtVector(width, -height, 0); + vertices[1] = AtVector(-width, -height, 0); + vertices[2] = AtVector(-width, height, 0); + AiNodeSetArray(node, "vertices", AiArrayConvert(4, 1, AI_TYPE_VECTOR, vertices)); + + SdfAssetPath texturePath; + if (light.GetTextureFileAttr().Get(&texturePath)) { + VtValue filename_vt(texturePath.GetResolvedPath()); + std::string filename = filename_vt.Get(); + if (!filename.empty()) { + // there's a texture filename, so we need to connect it to the color + std::string image_name(prim.GetPath().GetText()); + image_name += "/texture_file"; + AtNode *image = reader.createArnoldNode("image", image_name.c_str()); + + AiNodeSetStr(image, "filename", filename.c_str()); + AiNodeLink(image, "color", node); + + // now we need to export the intensity and exposure manually, + // because we have overridden the color + float intensity = 1.f; + light.GetIntensityAttr().Get(&intensity); + AiNodeSetFlt(node, "intensity", intensity); + float exposure = 0.f; + light.GetExposureAttr().Get(&exposure); + AiNodeSetFlt(node, "exposure", exposure); + } + } + + VtValue normalizeAttr; + if (light.GetNormalizeAttr().Get(&normalizeAttr)) { + AiNodeSetBool(node, "normalize", normalizeAttr.Get()); + } + + exportMatrix(prim, node, time); + readArnoldParameters(prim, reader, node, time); +} + +void UsdArnoldReadGeometryLight::read(const UsdPrim &prim, UsdArnoldReader &reader, bool create, bool convert) +{ + // First check if the target geometry is indeed a mesh, otherwise this won't + // work + UsdLuxGeometryLight light(prim); + + const TimeSettings &time = reader.getTimeSettings(); + + UsdRelationship rel = light.GetGeometryRel(); + SdfPathVector targets; + rel.GetTargets(&targets); + if (targets.empty()) { + return; + } + + // Need to export one mesh_light per target geometry + for (size_t i = 0; i < targets.size(); ++i) { + const SdfPath &geomPath = targets[i]; + // Should we instead call Load ? + UsdPrim targetPrim = reader.getStage()->GetPrimAtPath(geomPath); + if (!targetPrim.IsA()) { + continue; // arnold's mesh lights only support meshes + } + + AtNode *node = nullptr; + if (create) { + std::string lightName = prim.GetPath().GetText(); + if (i > 0) { + lightName += std::string("_") + std::string(targetPrim.GetPath().GetText()); + } + node = reader.createArnoldNode("mesh_light", lightName.c_str()); + } else { + node = AiNodeLookUpByName(targetPrim.GetPath().GetText(), reader.getProceduralParent()); + } + if (node == nullptr || !convert) { + continue; + } + + // ensure the target mesh is exported. + // FIXME : find a better way to avoid exporting the same data twice + reader.readPrimitive(targetPrim, true, false); + + exportLightCommon(light, node); + + VtValue normalizeAttr; + if (light.GetNormalizeAttr().Get(&normalizeAttr)) { + AiNodeSetBool(node, "normalize", normalizeAttr.Get()); + } + + exportMatrix(prim, node, time); + readArnoldParameters(prim, reader, node, time); + } +} diff --git a/translator/reader/read_light.h b/translator/reader/read_light.h new file mode 100755 index 0000000000..8cc8f58d92 --- /dev/null +++ b/translator/reader/read_light.h @@ -0,0 +1,34 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include + +#include + +#include +#include +#include + +#include "prim_reader.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +// Register readers for the USD builtin lights +REGISTER_PRIM_READER(UsdArnoldReadDistantLight); +REGISTER_PRIM_READER(UsdArnoldReadDomeLight); +REGISTER_PRIM_READER(UsdArnoldReadDiskLight); +REGISTER_PRIM_READER(UsdArnoldReadSphereLight); +REGISTER_PRIM_READER(UsdArnoldReadRectLight); +REGISTER_PRIM_READER(UsdArnoldReadGeometryLight); diff --git a/translator/reader/read_shader.cpp b/translator/reader/read_shader.cpp new file mode 100755 index 0000000000..141938655d --- /dev/null +++ b/translator/reader/read_shader.cpp @@ -0,0 +1,211 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "read_shader.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include "registry.h" +#include "utils.h" + +//-************************************************************************* + +PXR_NAMESPACE_USING_DIRECTIVE + +/** Export USD native shaders to Arnold + * + **/ +void UsdArnoldReadShader::read(const UsdPrim &prim, UsdArnoldReader &reader, bool create, bool convert) +{ + std::string nodeName = prim.GetPath().GetText(); + UsdShadeShader shader(prim); + // The "Shader Id" will tell us what is the type of the shader + TfToken id; + shader.GetIdAttr().Get(&id); + std::string shaderId = id.GetString(); + AtNode *node = NULL; + + // Support shaders having info:id = ArnoldStandardSurface + if (shaderId.length() > 6 && shaderId[0] == 'A' && shaderId[1] == 'r' && shaderId[2] == 'n' && shaderId[3] == 'o' && + shaderId[4] == 'l' && shaderId[5] == 'd') { + // We have a USD shader which shaderId is an arnold node name. The + // result should be equivalent to a custom USD node type with the same + // name. Let's search in the registry if there is a reader for that type + UsdArnoldPrimReader *primReader = reader.getRegistry()->getPrimReader(shaderId); + if (primReader) { + primReader->read(prim, reader, create, convert); // read this primitive + } + return; + } + // Support shaders having info:id = arnold:standard_surface + if (shaderId.length() > 7 && shaderId[0] == 'a' && shaderId[1] == 'r' && shaderId[2] == 'n' && shaderId[3] == 'o' && + shaderId[4] == 'l' && shaderId[5] == 'd' && shaderId[6] == ':') { + std::string shaderName = std::string("Arnold_") + shaderId.substr(7); + shaderName = makeCamelCase(shaderName); + UsdArnoldPrimReader *primReader = reader.getRegistry()->getPrimReader(shaderName); + if (primReader) { + primReader->read(prim, reader, create, convert); // read this primitive + } + return; + } + + if (shaderId == "UsdPreviewSurface") { + node = getNodeToConvert(reader, "standard_surface", nodeName.c_str(), create, convert); + if (!node) { + return; + } + + AiNodeSetRGB(node, "base_color", 0.18f, 0.18f, 0.18f); + exportParameter(shader, node, "diffuseColor", "base_color", reader); + AiNodeSetFlt(node, "base", 1.f); // scalar multiplier, set it to 1 + + AiNodeSetRGB(node, "emission_color", 0.f, 0.f, 0.f); + exportParameter(shader, node, "emissiveColor", "emission_color", reader); + AiNodeSetFlt(node, "emission", 1.f); // scalar multiplier, set it to 1 + + UsdShadeInput paramInput = shader.GetInput(TfToken("useSpecularWorkflow")); + int specularWorkflow = 0; + if (paramInput) { + paramInput.Get(&specularWorkflow); + } + + if (specularWorkflow == 1) { + // metallic workflow, set the specular color to white and use the + // metalness + AiNodeSetRGB(node, "specular_color", 1.f, 1.f, 1.f); + exportParameter(shader, node, "metallic", "metalness", reader); + } else { + AiNodeSetRGB(node, "specular_color", 1.f, 1.f, 1.f); + exportParameter(shader, node, "specularColor", "specular_color", reader); + // this is actually not correct. In USD, this is apparently the + // fresnel 0° "front-facing" specular color. Specular is considered + // to be always white for grazing angles + } + + AiNodeSetFlt(node, "specular_roughness", 0.5); + exportParameter(shader, node, "roughness", "specular_roughness", reader); + + AiNodeSetFlt(node, " specular_IOR ", 1.5); + exportParameter(shader, node, "ior", "specular_IOR", reader); + + AiNodeSetFlt(node, "coat", 0.f); + exportParameter(shader, node, "clearcoat", "coat", reader); + + AiNodeSetFlt(node, "coat_roughness", 0.01f); + exportParameter(shader, node, "clearcoatRoughness", "coat_roughness", reader); + + AiNodeSetFlt(node, "opacity", 1.f); + exportParameter(shader, node, "opacity", "opacity", reader); + + UsdShadeInput normalInput = shader.GetInput(TfToken("normal")); + if (normalInput && normalInput.HasConnectedSource()) { + // Usd expects a tangent normal map, let's create a normal_map + // shader, and connect it there + std::string normalMapName = nodeName + "@normal_map"; + AtNode *normalMap = reader.createArnoldNode("normal_map", normalMapName.c_str()); + AiNodeSetBool(normalMap, "color_to_signed", false); + exportParameter(shader, normalMap, "normal", "input", reader); + AiNodeLink(normalMap, "normal", node); + } + // We're not exporting displacement (float) as it's part of meshes in + // arnold. We're also not exporting the occlusion parameter (float), + // since it doesn't really apply for arnold. + + } else if (shaderId == "UsdUVTexture") { + node = getNodeToConvert(reader, "image", nodeName.c_str(), create, convert); + if (!node) { + return; + } + + // Texture Shader, we want to export it as arnold "image" node + exportParameter(shader, node, "file", "filename", reader); + + // In USD, meshes don't have a "default" UV set. So we always need to + // connect it to a user data shader. + exportParameter(shader, node, "st", "uvcoords", reader); + exportParameter(shader, node, "fallback", "missing_texture_color", reader); + + // wrapS, wrapT : "black, clamp, repeat, mirror" + // scale + // bias (UV offset) + } else if (shaderId == "UsdPrimvarReader_float") { + node = getNodeToConvert(reader, "user_data_float", nodeName.c_str(), create, convert); + if (!node) { + return; + } + exportParameter(shader, node, "varname", "attribute", reader); + exportParameter(shader, node, "fallback", "default", reader); + } else if (shaderId == "UsdPrimvarReader_float2") { + node = getNodeToConvert(reader, "user_data_rgb", nodeName.c_str(), create, convert); + if (!node) { + return; + } + exportParameter(shader, node, "varname", "attribute", reader); + UsdShadeInput paramInput = shader.GetInput(TfToken("fallback")); + GfVec2f vec2Val; + if (paramInput && paramInput.Get(&vec2Val)) { + AiNodeSetRGB(node, "default", vec2Val[0], vec2Val[1], 0.f); + } + } else if ( + shaderId == "UsdPrimvarReader_float3" || shaderId == "UsdPrimvarReader_normal" || + shaderId == "UsdPrimvarReader_point" || shaderId == "UsdPrimvarReader_vector") { + node = getNodeToConvert(reader, "user_data_rgb", nodeName.c_str(), create, convert); + if (!node) { + return; + } + exportParameter(shader, node, "varname", "attribute", reader); + exportParameter(shader, node, "fallback", "default", reader); + } else if (shaderId == "UsdPrimvarReader_float4") { + node = getNodeToConvert(reader, "user_data_rgba", nodeName.c_str(), create, convert); + if (!node) { + return; + } + exportParameter(shader, node, "varname", "attribute", reader); + exportParameter(shader, node, "fallback", "default", reader); + } else if (shaderId == "UsdPrimvarReader_int") { + node = getNodeToConvert(reader, "user_data_int", nodeName.c_str(), create, convert); + if (!node) { + return; + } + exportParameter(shader, node, "varname", "attribute", reader); + exportParameter(shader, node, "fallback", "default", reader); + } else if (shaderId == "UsdPrimvarReader_string") { + node = getNodeToConvert(reader, "user_data_string", nodeName.c_str(), create, convert); + if (!node) { + return; + } + exportParameter(shader, node, "varname", "attribute", reader); + exportParameter(shader, node, "fallback", "default", reader); + } else + { + // support info:id = standard_surface + std::string shaderName = std::string("Arnold_") + shaderId; + shaderName = makeCamelCase(shaderName); + UsdArnoldPrimReader *primReader = reader.getRegistry()->getPrimReader(shaderName); + if (primReader) { + primReader->read(prim, reader, create, convert); // read this primitive + } + } + // User-data matrix isn't supported in arnold + if (convert) { + const TimeSettings &time = reader.getTimeSettings(); + readArnoldParameters(prim, reader, node, time); + } +} diff --git a/translator/reader/read_shader.h b/translator/reader/read_shader.h new file mode 100755 index 0000000000..6f073831db --- /dev/null +++ b/translator/reader/read_shader.h @@ -0,0 +1,29 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include + +#include + +#include +#include +#include + +#include "prim_reader.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +// Register readers for the USD builtin lights +REGISTER_PRIM_READER(UsdArnoldReadShader); diff --git a/translator/reader/reader.cpp b/translator/reader/reader.cpp new file mode 100755 index 0000000000..03dd137d3e --- /dev/null +++ b/translator/reader/reader.cpp @@ -0,0 +1,342 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "reader.h" + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "prim_reader.h" +#include "registry.h" + +//-************************************************************************* + +PXR_NAMESPACE_USING_DIRECTIVE + +// global reader registry, will be used in the default case +static UsdArnoldReaderRegistry *s_readerRegistry = NULL; + +UsdArnoldReader::~UsdArnoldReader() +{ + // What do we want to do at destruction here ? + // Should we delete the created nodes in case there was no procParent ? +} + +void UsdArnoldReader::read(const std::string &filename, AtArray *overrides, const std::string &path) +{ + // Nodes were already exported, should we skip here, + // or should we just append the new nodes ? + if (!_nodes.empty()) { + return; + } + + SdfLayerRefPtr rootLayer = SdfLayer::FindOrOpen(filename); + + if (overrides == nullptr || AiArrayGetNumElements(overrides) == 0) { + UsdStageRefPtr stage = UsdStage::Open(rootLayer, UsdStage::LoadAll); + readStage(stage, path); + } else { + auto getLayerName = []() -> std::string { + static int counter = 0; + std::stringstream ss; + ss << "anonymous__override__" << counter++ << ".usda"; + return ss.str(); + }; + + auto overrideLayer = SdfLayer::CreateAnonymous(getLayerName()); + const auto overrideCount = AiArrayGetNumElements(overrides); + + std::vector layerNames; + layerNames.reserve(overrideCount); + // Make sure they kep around after the loop scope ends. + std::vector layers; + layers.reserve(overrideCount); + + for (auto i = decltype(overrideCount){0}; i < overrideCount; ++i) { + auto layer = SdfLayer::CreateAnonymous(getLayerName()); + if (layer->ImportFromString(AiArrayGetStr(overrides, i).c_str())) { + layerNames.emplace_back(layer->GetIdentifier()); + layers.push_back(layer); + } + } + + overrideLayer->SetSubLayerPaths(layerNames); + auto stage = UsdStage::Open(rootLayer, overrideLayer, UsdStage::LoadAll); + + readStage(stage, path); + } +} + +struct UsdThreadData { + UsdThreadData() : threadId(0), threadCount(0), reader(nullptr), rootPrim(nullptr), create(false), convert(false) {} + + unsigned int threadId; + unsigned int threadCount; + UsdArnoldReader *reader; + UsdPrim *rootPrim; + bool create; + bool convert; +}; + +unsigned int UsdArnoldReader::RenderThread(void *data) +{ + UsdThreadData *threadData = (UsdThreadData *)data; + if (!threadData) { + return 0; + } + + size_t index = 0; + size_t threadId = threadData->threadId; + size_t threadCount = threadData->threadCount; + bool multithread = (threadCount > 1); + bool create = threadData->create; + bool convert = threadData->convert; + UsdPrim *rootPrim = threadData->rootPrim; + UsdArnoldReader *reader = threadData->reader; + + UsdPrimRange range = (rootPrim && false) ? UsdPrimRange(*rootPrim) : reader->getStage()->Traverse(); + for (auto iter = range.begin(); iter != range.end(); ++iter) { + // Each thread only considers 1 every thread count primitives + if (multithread && ((index++ + threadId) % threadCount)) { + continue; + } + const UsdPrim &prim(*iter); + reader->readPrimitive(prim, create, convert); + // Note: if the registry didn't find any primReader, we're not prunning + // its children nodes, but just skipping this one. + } + return 0; +} + +void UsdArnoldReader::readStage(UsdStageRefPtr stage, const std::string &path) +{ + // set the stage while we're reading + _stage = stage; + + // FIXME : should we flatten the UsdStage or not ? + // _stage->Flatten(); + + if (_debug) { + std::string txt("==== Initializing Usd Reader "); + if (_procParent) { + txt += " for procedural "; + txt += AiNodeGetName(_procParent); + } + AiMsgWarning(txt.c_str()); + } + + // eventually use a dedicated registry + if (_registry == NULL) { + // No registry was set (default), let's use the global one + if (s_readerRegistry == NULL) { + s_readerRegistry = new UsdArnoldReaderRegistry(); // initialize the global registry + } + + _registry = s_readerRegistry; + } + + UsdPrim rootPrim; + UsdPrim *rootPrimPtr = nullptr; + + if (!path.empty()) { + SdfPath sdfPath(path); + rootPrim = _stage->GetPrimAtPath(sdfPath); + if ((!rootPrim) || (!rootPrim.IsActive())) { + AiMsgError( + "[usd] %s : Object Path %s is not valid", (_procParent) ? AiNodeGetName(_procParent) : "", + path.c_str()); + return; + } + rootPrimPtr = &rootPrim; + } + + if (_threadCount == 1) { + // Just for safety, I'm doing a special case for single thread, but this + // code should be unified with the multi-thread code + UsdPrimRange range = (rootPrimPtr) ? UsdPrimRange(*rootPrimPtr) : _stage->Traverse(); + + for (auto iter = range.begin(); iter != range.end(); ++iter) { + const UsdPrim &prim(*iter); + readPrimitive(prim, true, true); + } + } else { + size_t threadCount = _threadCount; // do we want to do something + // automatic when threadCount = 0 ? + + // Multi-thread inspection. We need to split the task in two. + // - First, we traverse the Usd stage to create all the nodes + // - Second, we traverse again the stage in order to do the actual + // conversion + + // This is necessary to ensure that all nodes are properly created + // before setting eventual links between them + + std::vector threadData(threadCount); + std::vector threads(threadCount, nullptr); + + // First we want to traverse the stage in order to create all nodes + for (size_t i = 0; i < threadCount; ++i) { + threadData[i].threadId = i; + threadData[i].threadCount = threadCount; + threadData[i].reader = new UsdArnoldReader(*this); + threadData[i].rootPrim = rootPrimPtr; + threadData[i].create = true; + threadData[i].convert = false; + threads[i] = AiThreadCreate(UsdArnoldReader::RenderThread, &threadData[i], AI_PRIORITY_HIGH); + } + + for (size_t i = 0; i < threadCount; ++i) { + AiThreadWait(threads[i]); + AiThreadClose(threads[i]); + _nodes.insert(_nodes.end(), threadData[i].reader->_nodes.begin(), threadData[i].reader->_nodes.end()); + threads[i] = nullptr; + } + // At this point all the nodes were created, let's now do the actual + // conversion + for (size_t i = 0; i < threadCount; ++i) { + threadData[i].create = false; + threadData[i].convert = true; + threads[i] = AiThreadCreate(UsdArnoldReader::RenderThread, &threadData[i], AI_PRIORITY_HIGH); + } + for (size_t i = 0; i < threadCount; ++i) { + AiThreadWait(threads[i]); + AiThreadClose(threads[i]); + threads[i] = nullptr; + } + + for (size_t i = 0; i < threadCount; ++i) { + delete threadData[i].reader; + } + } + + _stage = UsdStageRefPtr(); // clear the shared pointer, delete the stage +} + +void UsdArnoldReader::readPrimitive(const UsdPrim &prim, bool create, bool convert) +{ + std::string objName = prim.GetPath().GetText(); + std::string objType = prim.GetTypeName().GetText(); + + UsdArnoldPrimReader *primReader = _registry->getPrimReader(objType); + if (primReader) { + if (_debug) { + std::string txt; + if (create) { + txt += "Create "; + } + if (convert) { + if (create) { + txt += "and "; + } + txt += "Convert "; + } + + txt += "Object "; + txt += objName; + txt += " (type: "; + txt += objType; + txt += ")"; + + AiMsgWarning(txt.c_str()); + } + + primReader->read(prim, *this, create, convert); // read this primitive + } +} +void UsdArnoldReader::setThreadCount(unsigned int t) { _threadCount = t; } +void UsdArnoldReader::setFrame(float frame) +{ + clearNodes(); // FIXME do we need to clear here ? We should rather re-export + // the data + _time.frame = frame; +} + +void UsdArnoldReader::setMotionBlur(bool motion_blur, float motion_start, float motion_end) +{ + clearNodes(); // FIXME do we need to clear here ? We should rather re-export + // the data + _time.motion_blur = motion_blur; + _time.motion_start = motion_start; + _time.motion_end = motion_end; +} + +void UsdArnoldReader::setDebug(bool b) +{ + // We obviously don't need to clear the data here, but it will make it + // simpler since the data will be re-generated + clearNodes(); + _debug = b; +} + +void UsdArnoldReader::clearNodes() +{ + // FIXME should we also delete the nodes if there is a proc parent ? + if (_procParent == NULL) { + // No parent proc, this means we should delete all nodes ourselves + for (size_t i = 0; i < _nodes.size(); ++i) { + AiNodeDestroy(_nodes[i]); + } + } + _nodes.clear(); +} + +void UsdArnoldReader::setProceduralParent(const AtNode *node) +{ + // should we clear the nodes when a new procedural parent is set ? + clearNodes(); + _procParent = node; + _universe = (node) ? AiNodeGetUniverse(node) : NULL; +} + +void UsdArnoldReader::setRegistry(UsdArnoldReaderRegistry *registry) { _registry = registry; } +void UsdArnoldReader::setUniverse(AtUniverse *universe) +{ + if (_procParent) { + if (universe != _universe) { + AiMsgError( + "UsdArnoldReader: we cannot set a universe that is different " + "from the procedural parent"); + } + return; + } + // should we clear the nodes when a new universe is set ? + clearNodes(); + _universe = universe; +} + +AtNode *UsdArnoldReader::createArnoldNode(const char *type, const char *name, bool *existed) +{ + AtNode *node = AiNodeLookUpByName(name, _procParent); + if (existed) { + *existed = (node != NULL); + } + + if (node) + return node; // FIXME should we test if the nodeType is different ? + + node = AiNode(_universe, type, name, _procParent); + if (node) { + _nodes.push_back(node); + } + + return node; +} diff --git a/translator/reader/reader.h b/translator/reader/reader.h new file mode 100755 index 0000000000..07c12524b0 --- /dev/null +++ b/translator/reader/reader.h @@ -0,0 +1,78 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include + +#include +#include +#include +#include +#include "utils.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +class UsdArnoldReaderRegistry; + +/** + * Class handling the translation of USD data to Arnold + **/ + +class UsdArnoldReader { +public: + UsdArnoldReader() : _procParent(NULL), _universe(NULL), _registry(NULL), _debug(false), _threadCount(1) {} + ~UsdArnoldReader(); + + void read(const std::string &filename, AtArray *overrides, + const std::string &path = ""); // read a USD file + void readStage(UsdStageRefPtr stage, + const std::string &path = ""); // read a specific UsdStage + void readPrimitive(const UsdPrim &prim, bool create = true, bool convert = true); + + // Create an Arnold node of a given type, with a given name. If a node + // already exists with this name, return the existing one. + AtNode *createArnoldNode(const char *type, const char *name, bool *existed = NULL); + void clearNodes(); + + void setProceduralParent(const AtNode *node); + void setUniverse(AtUniverse *universe); + void setRegistry(UsdArnoldReaderRegistry *registry); + void setFrame(float frame); + void setMotionBlur(bool motion_blur, float motion_start = 0.f, float motion_end = 0.f); + void setDebug(bool b); + void setThreadCount(unsigned int t); + + const UsdStageRefPtr &getStage() const { return _stage; } + const std::vector &getNodes() const { return _nodes; } + float getFrame() const { return _time.frame; } + UsdArnoldReaderRegistry *getRegistry() { return _registry; } + AtUniverse *getUniverse() { return _universe; } + const AtNode *getProceduralParent() const { return _procParent; } + bool getDebug() const { return _debug; } + const TimeSettings &getTimeSettings() const { return _time; } + + static unsigned int RenderThread(void *data); + +private: + const AtNode *_procParent; // the created nodes are children of a procedural parent + AtUniverse *_universe; // only set if a specific universe is being used + UsdArnoldReaderRegistry *_registry; // custom registry used for this reader. If null, a global + // registry will be used. + TimeSettings _time; + bool _debug; + unsigned int _threadCount; + UsdStageRefPtr _stage; // current stage being read. Will be cleared once + // finished reading + std::vector _nodes; +}; \ No newline at end of file diff --git a/translator/reader/registry.cpp b/translator/reader/registry.cpp new file mode 100755 index 0000000000..041fdb0985 --- /dev/null +++ b/translator/reader/registry.cpp @@ -0,0 +1,115 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "registry.h" + +#include +#include +#include +#include +#include + +#include "read_arnold_type.h" +#include "read_geometry.h" +#include "read_light.h" +#include "read_shader.h" +#include "utils.h" +//-************************************************************************* + +PXR_NAMESPACE_USING_DIRECTIVE + +UsdArnoldReaderRegistry::UsdArnoldReaderRegistry() +{ + // First, let's register all the prim readers that we've hardcoded for USD + // builtin types + + // USD builtin Shapes + registerReader("Mesh", new UsdArnoldReadMesh()); + registerReader("Curves", new UsdArnoldReadCurves()); + registerReader("Points", new UsdArnoldReadPoints()); + registerReader("Cube", new UsdArnoldReadCube()); + registerReader("Sphere", new UsdArnoldReadSphere()); + registerReader("Cylinder", new UsdArnoldReadCylinder()); + registerReader("Cone", new UsdArnoldReadCone()); + registerReader("Capsule", new UsdArnoldReadCapsule()); + registerReader("PointInstancer", new UsdArnoldReadUnsupported("PointInstancer")); + registerReader("Nurbs", new UsdArnoldReadUnsupported("Nurbs")); + + // USD builtin Lights + registerReader("DistantLight", new UsdArnoldReadDistantLight()); + registerReader("DomeLight", new UsdArnoldReadDomeLight()); + registerReader("DiskLight", new UsdArnoldReadDiskLight()); + registerReader("SphereLight", new UsdArnoldReadSphereLight()); + registerReader("RectLight", new UsdArnoldReadRectLight()); + registerReader("GeometryLight", new UsdArnoldReadGeometryLight()); + + // USD Shaders (builtin, or custom ones, including arnold) + registerReader("Shader", new UsdArnoldReadShader()); + + // Now let's iterate over all the arnold classes known at this point + bool universeCreated = false; + // If a universe is already active, we can just use it, otherwise we need to + // call AiBegin. + // But if we do so, we'll have to call AiEnd() when we finish + if (!AiUniverseIsActive()) { + AiBegin(); + universeCreated = true; + // FIXME: should we call AiLoadPlugins here, or will it be done + // automatically ? + } + + // Iterate over all node types + AtNodeEntryIterator *nodeEntryIter = AiUniverseGetNodeEntryIterator(AI_NODE_ALL); + while (!AiNodeEntryIteratorFinished(nodeEntryIter)) { + AtNodeEntry *nodeEntry = AiNodeEntryIteratorGetNext(nodeEntryIter); + std::string entryName = AiNodeEntryGetName(nodeEntry); + + // Do we need different behaviour depending on the entry type name ? + std::string entryTypeName = AiNodeEntryGetTypeName(nodeEntry); + + // FIXME: should we switch to camel case for usd node types ? + std::string usdName = makeCamelCase(entryName); + if (usdName.length() == 0) { + continue; + } + usdName[0] = toupper(usdName[0]); + usdName = std::string("Arnold") + usdName; + registerReader(usdName, new UsdArnoldReadArnoldType(entryName, entryTypeName)); + } + AiNodeEntryIteratorDestroy(nodeEntryIter); + + if (universeCreated) { + AiEnd(); + } +} +UsdArnoldReaderRegistry::~UsdArnoldReaderRegistry() +{ + // Delete all the prim readers that were registed here + std::unordered_map::iterator it = _readersMap.begin(); + std::unordered_map::iterator itEnd = _readersMap.end(); + + for (; it != itEnd; ++it) { + delete it->second; + } +} + +void UsdArnoldReaderRegistry::registerReader(const std::string &primName, UsdArnoldPrimReader *primReader) +{ + std::unordered_map::iterator it = _readersMap.find(primName); + if (it != _readersMap.end()) { + // we have already registered a reader for this node type, let's delete + // the existing one and override it + delete it->second; + } + _readersMap[primName] = primReader; +} diff --git a/translator/reader/registry.h b/translator/reader/registry.h new file mode 100755 index 0000000000..db975a33b5 --- /dev/null +++ b/translator/reader/registry.h @@ -0,0 +1,58 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include + +#include + +#include +#include +#include + +class UsdArnoldPrimReader; + +PXR_NAMESPACE_USING_DIRECTIVE + +/** + * This Registry stores which UsdArnoldPrimReader must be used to read a + *UsdPrim of a given type. In its constructor, it will iterate over all known + *arnold node types and register the corresponding UsdArnoldPrimReaders. This + *class can be derived if we need to customize the list of prim readers to be + *used + **/ + +class UsdArnoldReaderRegistry { +public: + UsdArnoldReaderRegistry(); + virtual ~UsdArnoldReaderRegistry(); + + // Register a new prim reader to this type of usd primitive. + // If an existing one was previously registed for this same type, it will be + // deleted and overridden + void registerReader(const std::string &primName, UsdArnoldPrimReader *primReader); + + UsdArnoldPrimReader *getPrimReader(const std::string &primName) + { + std::unordered_map::iterator it = _readersMap.find(primName); + if (it == _readersMap.end()) { + return NULL; // return NULL if no reader was registered for this + // node type, it will be skipped + } + return it->second; + } + +private: + std::unordered_map _readersMap; +}; diff --git a/translator/reader/utils.cpp b/translator/reader/utils.cpp new file mode 100755 index 0000000000..84d6bed395 --- /dev/null +++ b/translator/reader/utils.cpp @@ -0,0 +1,489 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "utils.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "reader.h" +//-************************************************************************* + +PXR_NAMESPACE_USING_DIRECTIVE + +static inline void getMatrix(const UsdGeomXformable &xformable, AtMatrix &matrix, float frame) +{ + GfMatrix4d xform; + bool dummyBool = false; + xformable.GetLocalTransformation(&xform, &dummyBool, frame); + const double *array = xform.GetArray(); + for (unsigned int i = 0; i < 4; ++i) + for (unsigned int j = 0; j < 4; ++j) + matrix[i][j] = array[4 * i + j]; +} +/** Export Xformable transform as an arnold shape "matrix" + */ +void exportMatrix(const UsdPrim &prim, AtNode *node, const TimeSettings &time) +{ + UsdGeomXformable xformable(prim); + bool animated = xformable.TransformMightBeTimeVarying(); + AtMatrix matrix; + if (time.motion_blur && animated) { + // animated matrix, need to make it an array + GfInterval interval(time.start(), time.end(), false, false); + std::vector timeSamples; + xformable.GetTimeSamplesInInterval(interval, &timeSamples); + size_t numKeys = AiMax(int(timeSamples.size()), (int)1); + numKeys += 2; // need to add the start end end keys (interval has open bounds) + AtArray *array = AiArrayAllocate(1, numKeys, AI_TYPE_MATRIX); + float timeStep = float(interval.GetMax() - interval.GetMin()) / int(numKeys - 1); + float timeVal = interval.GetMin(); + for (size_t i = 0; i < numKeys; i++, timeVal += timeStep) { + getMatrix(xformable, matrix, timeVal); + AiArraySetMtx(array, i, matrix); + } + AiNodeSetArray(node, "matrix", array); + AiNodeSetFlt(node, "motion_start", time.motion_start); + AiNodeSetFlt(node, "motion_end", time.motion_end); + } else { + getMatrix(xformable, matrix, time.frame); + // set the attribute + AiNodeSetMatrix(node, "matrix", matrix); + } +} +// Export a primvar +template +bool exportPrimvar( + const VtValue &vtValue, const VtIntArray &vtIndices, const TfToken &name, const SdfValueTypeName &typeName, + const TfToken &interpolation, const UsdPrim &prim, AtNode *node, MeshOrientation *orientation = NULL) +{ + if (!vtValue.IsHolding>()) + return false; + + TfToken arnoldName = name; + bool needDeclare = true; + + // Convert interpolation -> scope + // + // USD Interpolation determines how the Primvar interpolates over a + // geometric primitive: + // constant One value remains constant over the entire surface + // primitive. + // uniform One value remains constant for each uv patch segment of the + // surface primitive (which is a face for meshes). + // varying Four values are interpolated over each uv patch segment of + // the surface. Bilinear interpolation is used for interpolation + // between the four values. + // vertex Values are interpolated between each vertex in the surface + // primitive. The basis function of the surface is used for + // interpolation between vertices. + // faceVarying For polygons and subdivision surfaces, four values are + // interpolated over each face of the mesh. Bilinear + // interpolation is used for interpolation between the four + // values. + // + // There are four kinds of user-defined data in Arnold: + // + // constant constant parameters are data that are defined on a + // per-object basis and do not vary across the surface of that + // object. + // uniform uniform parameters are data that are defined on a "per-face" + // basis. During subdivision (if appropriate) values are not + // interpolated. Instead, the newly subdivided faces will + // contain the value of their "parent" face. + // varying varying parameters are data that are defined on a per-vertex + // basis. During subdivision (if appropriate), the values at the + // new vertices are interpolated from the values at the old + // vertices. The user should only create parameters of + // "interpolatable" variable types (such as floats, colors, + // etc.) + // indexed indexed parameters are data that are defined on a + // per-face-vertex basis. During subdivision (if appropriate), + // the values at the new vertices are interpolated from the + // values at the old vertices, preserving edges where values + // were not shared. The user should only create parameters of + // "interpolatable" variable types (such as floats, colors, + // etc.) + std::string declaration = + (interpolation == UsdGeomTokens->uniform) + ? "uniform " + : (interpolation == UsdGeomTokens->varying) + ? "varying " + : (interpolation == UsdGeomTokens->vertex) + ? "varying " + : (interpolation == UsdGeomTokens->faceVarying) ? "indexed " : "constant "; + + int arnoldAPIType; + if (std::is_same::value) { + declaration += "VECTOR2"; + arnoldAPIType = AI_TYPE_VECTOR2; + + // A special case for UVs. + if (name == "uv") { + arnoldName = TfToken("uvlist"); + needDeclare = false; + } + } else if (std::is_same::value) { + TfToken role = typeName.GetRole(); + if (role == SdfValueRoleNames->Color) { + declaration += "RGB"; + arnoldAPIType = AI_TYPE_RGB; + } else { + declaration += "VECTOR"; + arnoldAPIType = AI_TYPE_VECTOR; + } + } else if (std::is_same::value) { + declaration += "FLOAT"; + arnoldAPIType = AI_TYPE_FLOAT; + } else if (std::is_same::value) { + declaration += "INT"; + arnoldAPIType = AI_TYPE_INT; + } else { + // Not supported. + return false; + } + + // Declare a user-defined parameter. + if (needDeclare) { + AiNodeDeclare(node, arnoldName.GetText(), declaration.c_str()); + } + + // Constant USD attributs are provided as an array of one element. + if (interpolation == UsdGeomTokens->constant) { + if (std::is_same::value) { + VtArray vecArray = vtValue.Get>(); + GfVec3f value = vecArray[0]; + + TfToken role = typeName.GetRole(); + if (role == SdfValueRoleNames->Color) { + AiNodeSetRGB(node, arnoldName.GetText(), value[0], value[1], value[2]); + } else { + AiNodeSetVec(node, arnoldName.GetText(), value[0], value[1], value[2]); + } + } else if (std::is_same::value) { + auto vector = vtValue.Get>()[0]; + AiNodeSetVec2(node, arnoldName.GetText(), vector[0], vector[1]); + } else if (std::is_same::value) { + AiNodeSetFlt(node, arnoldName.GetText(), vtValue.Get>()[0]); + } else if (std::is_same::value) { + AiNodeSetInt(node, arnoldName.GetText(), vtValue.Get>()[0]); + } + } else { + const VtArray &rawVal = vtValue.Get>(); + AiNodeSetArray(node, arnoldName.GetText(), AiArrayConvert(rawVal.size(), 1, arnoldAPIType, rawVal.data())); + + if (interpolation == UsdGeomTokens->faceVarying) { + const std::string indexName = name.GetString() + "idxs"; + std::vector indexes; + + if (vtIndices.empty()) { + // Arnold doesn't have facevarying iterpolation. It has indexed + // instead. So it means it's necessary to generate indexes for + // this type. + // TODO: Try to generate indexes only once and use it for + // several primvars. + + indexes.resize(rawVal.size()); + // Fill it with 0, 1, ..., 99. + std::iota(std::begin(indexes), std::end(indexes), 0); + } else { + // We need to use indexes and we can't use vtIndices because we + // need unsigned int. Converting int to unsigned int. + indexes.resize(vtIndices.size()); + std::copy(vtIndices.begin(), vtIndices.end(), indexes.begin()); + } + + // If the mesh has left-handed orientation, we need to invert the + // indices of primvars for each face + if (orientation) + orientation->orient_face_index_attribute(indexes); + + AiNodeSetArray(node, indexName.c_str(), AiArrayConvert(indexes.size(), 1, AI_TYPE_UINT, indexes.data())); + } + } + return true; +} + +/** + * Export all primvars from this shape, and set them as arnold user data + * + **/ + +void exportPrimvars(const UsdPrim &prim, AtNode *node, const TimeSettings &time, MeshOrientation *orientation) +{ + assert(prim); + UsdGeomImageable imageable = UsdGeomImageable(prim); + assert(imageable); + float frame = time.frame; + + for (const UsdGeomPrimvar &primvar : imageable.GetPrimvars()) { + TfToken name; + SdfValueTypeName typeName; + TfToken interpolation; + int elementSize; + + primvar.GetDeclarationInfo(&name, &typeName, &interpolation, &elementSize); + + // Resolve the value + VtValue vtValue; + VtIntArray vtIndices; + if (interpolation == UsdGeomTokens->constant) { + if (!primvar.Get(&vtValue, frame)) { + continue; + } + } else if (interpolation == UsdGeomTokens->faceVarying && primvar.IsIndexed()) { + // It's an indexed value. We don't want to flatten it because it + // breaks subdivs. + if (!primvar.Get(&vtValue, frame)) { + continue; + } + + if (!primvar.GetIndices(&vtIndices, frame)) { + continue; + } + } else { + // USD comments suggest using using the ComputeFlattened() API + // instead of Get even if they produce the same data. + if (!primvar.ComputeFlattened(&vtValue, frame)) { + continue; + } + } + + if (vtValue.IsHolding>()) + export_primvar(vtValue, vtIndices, name, typeName, interpolation, prim, node, orientation); + else if (vtValue.IsHolding>()) + export_primvar(vtValue, vtIndices, name, typeName, interpolation, prim, node, orientation); + else if (vtValue.IsHolding>()) + export_primvar(vtValue, vtIndices, name, typeName, interpolation, prim, node, orientation); + else if (vtValue.IsHolding>()) + export_primvar(vtValue, vtIndices, name, typeName, interpolation, prim, node, orientation); + } +} + +// Export the materials / shaders assigned to a shape (node) +void exportMaterialBinding(const UsdPrim &prim, AtNode *node, UsdArnoldReader &reader) +{ + UsdShadeMaterial mat = UsdShadeMaterial::GetBoundMaterial(prim); + if (!mat) + return; + + AtNode *shader = NULL; + TfToken arnoldContext("arnold"); + UsdShadeShader surface = mat.ComputeSurfaceSource(); + if (!surface) + surface = mat.ComputeSurfaceSource(arnoldContext); + + + if (surface) { + reader.readPrimitive(surface.GetPrim(), true, false); + shader = AiNodeLookUpByName(surface.GetPath().GetText(), reader.getProceduralParent()); + if (shader) + AiNodeSetPtr(node, "shader", shader); + } + + // We have a single "shader" binding in arnold, whereas USD has "surface" + // and "volume" For now we export volume only if surface is empty. + if (shader == NULL) { + UsdShadeShader volume = mat.ComputeVolumeSource(); + if (!volume) + volume = mat.ComputeVolumeSource(arnoldContext); + + if (volume) { + reader.readPrimitive(volume.GetPrim(), true, false); + shader = AiNodeLookUpByName(volume.GetPath().GetText(), reader.getProceduralParent()); + AiNodeSetPtr(node, "shader", shader); + } + } + + // Now export displacement + if (AiNodeIs(node, AtString("polymesh"))) { + UsdShadeShader displacement = mat.ComputeDisplacementSource(); + if (!displacement) + displacement = mat.ComputeDisplacementSource(arnoldContext); + + if (displacement) { + reader.readPrimitive(displacement.GetPrim(), true, false); + shader = AiNodeLookUpByName(displacement.GetPath().GetText(), reader.getProceduralParent()); + AiNodeSetPtr(node, "disp_map", shader); + } + } +} + +/** + * Export a specific shader parameter from USD to Arnold + * + **/ + +void exportParameter( + UsdShadeShader &shader, AtNode *node, const std::string &usdName, const std::string &arnoldName, + UsdArnoldReader &reader) +{ + if (node == NULL) + return; + + const AtNodeEntry *nentry = AiNodeGetNodeEntry(node); + const AtParamEntry *paramEntry = AiNodeEntryLookUpParameter(nentry, AtString(arnoldName.c_str())); + int paramType = AiParamGetType(paramEntry); + + if (nentry == NULL || paramEntry == NULL) { + std::string msg = "Couldn't find attribute "; + msg += arnoldName; + msg += " from node "; + msg += AiNodeGetName(node); + AiMsgWarning(msg.c_str()); + return; + } + + UsdShadeInput paramInput = shader.GetInput(TfToken(usdName.c_str())); + if (paramInput) { + SdfPathVector sourcePaths; + + // First check if there's a connection to this input attribute + if (paramInput.HasConnectedSource() && paramInput.GetRawConnectedSourcePaths(&sourcePaths) && + !sourcePaths.empty()) { + // just take the first target..., or should we check if the + // attribute is an array ? + UsdPrim targetPrim = reader.getStage()->GetPrimAtPath(sourcePaths[0].GetPrimPath()); + + // Note that we're not considering which shader output parameter was + // connected to this input. We might want to do in some special + // cases (eg if a float attribute is connected to "outputs.r") + if (targetPrim && targetPrim.GetTypeName() == TfToken("Shader")) { + reader.readPrimitive(targetPrim, true, false); + // the above call should have created the shader already + AtNode *target = AiNodeLookUpByName(targetPrim.GetPath().GetText(), reader.getProceduralParent()); + if (target) { + AiNodeLink(target, arnoldName.c_str(), node); + } + } + } else { + // Just set the attribute value. + // Switch depending on arnold attr type + switch (paramType) { + { + case AI_TYPE_BOOLEAN: + bool boolVal; + if (paramInput.Get(&boolVal)) + AiNodeSetBool(node, arnoldName.c_str(), boolVal); + break; + } + { + case AI_TYPE_BYTE: + unsigned char charVal; + if (paramInput.Get(&charVal)) + AiNodeSetByte(node, arnoldName.c_str(), charVal); + break; + } + { + case AI_TYPE_UINT: + unsigned int uintVal; + if (paramInput.Get(&uintVal)) + AiNodeSetUInt(node, arnoldName.c_str(), uintVal); + break; + } + { + case AI_TYPE_INT: + int intVal; + if (paramInput.Get(&intVal)) + AiNodeSetInt(node, arnoldName.c_str(), intVal); + break; + } + { + case AI_TYPE_FLOAT: + float fltVal; + if (paramInput.Get(&fltVal)) + AiNodeSetFlt(node, arnoldName.c_str(), fltVal); + break; + } + { + case AI_TYPE_VECTOR2: + GfVec2f vec2Val; + if (paramInput.Get(&vec2Val)) + AiNodeSetVec2(node, arnoldName.c_str(), vec2Val[0], vec2Val[1]); + break; + } + { + case AI_TYPE_VECTOR: + GfVec3f vecVal; + if (paramInput.Get(&vecVal)) + AiNodeSetVec(node, arnoldName.c_str(), vecVal[0], vecVal[1], vecVal[2]); + break; + } + { + case AI_TYPE_RGB: + GfVec3f vecVal; + if (paramInput.Get(&vecVal)) + AiNodeSetRGB(node, arnoldName.c_str(), vecVal[0], vecVal[1], vecVal[2]); + break; + } + { + case AI_TYPE_RGBA: + GfVec4f rgbaVal; + if (paramInput.Get(&rgbaVal)) + AiNodeSetRGBA(node, arnoldName.c_str(), rgbaVal[0], rgbaVal[1], rgbaVal[2], rgbaVal[3]); + break; + } + { + case AI_TYPE_STRING: + TfToken tokenVal; + if (paramInput.Get(&tokenVal)) { + AiNodeSetStr(node, arnoldName.c_str(), tokenVal.GetText()); + } else { + // "Asset" parameters (for filenames) won't work + // with TfToken, let's try again with a SdfAssetPath + SdfAssetPath assetPath; + if (paramInput.Get(&assetPath)) { + // Should we use the resolved path here ? I'm + // doing it because Arnold might not know the + // usd "search" paths. This happens during the + // usd_procedural expansion, so it shouldn't be + // a problem. + AiNodeSetStr(node, arnoldName.c_str(), assetPath.GetResolvedPath().c_str()); + } + } + break; + } + default: + // Arrays not supported yet + break; + } + } + } +} + +AtNode *getNodeToConvert(UsdArnoldReader &reader, const char *nodeType, const char *nodeName, bool create, bool convert) +{ + AtNode *node = nullptr; + if (create) { + node = reader.createArnoldNode(nodeType, nodeName); + } else { + // check if the node already existed + node = AiNodeLookUpByName(nodeName, reader.getProceduralParent()); + } + if (!convert) + return nullptr; + + return node; +} diff --git a/translator/reader/utils.h b/translator/reader/utils.h new file mode 100755 index 0000000000..d32bedda37 --- /dev/null +++ b/translator/reader/utils.h @@ -0,0 +1,365 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include + +#include +#include +#include + +#include +#include +#include + +#include "../utils/utils.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +class UsdArnoldReader; + +struct MeshOrientation { + MeshOrientation() : reverse(false) {} + + VtIntArray nsides_array; + bool reverse; + template + void orient_face_index_attribute(T& attr); +}; + +struct TimeSettings { + TimeSettings() : frame(1.f), motion_blur(false), motion_start(1.f), motion_end(1.f) {} + + float frame; + bool motion_blur; + float motion_start; + float motion_end; + + float start() const { return (motion_blur) ? motion_start + frame : frame; } + float end() const { return (motion_blur) ? motion_end + frame : frame; } +}; + +// Reverse an attribute of the face. Basically, it converts from the clockwise +// to the counterclockwise and back. +template +void MeshOrientation::orient_face_index_attribute(T& attr) +{ + if (!reverse) + return; + + size_t counter = 0; + for (auto npoints : nsides_array) { + for (size_t j = 0; j < npoints / 2; j++) { + size_t from = counter + j; + size_t to = counter + npoints - 1 - j; + std::swap(attr[from], attr[to]); + } + counter += npoints; + } +} + +/** Export Xformable transform as an arnold shape "matrix" + * TODO: motion blur + */ +void exportMatrix(const UsdPrim& prim, AtNode* node, const TimeSettings& time); + +/** Convert a USD array attribute (type U), to an Arnold array (type A). + * When both types are identical, we can simply their pointer to create the + *array. Otherwise we need to copy the data first + **/ +template +size_t exportArray(UsdAttribute attr, AtNode* node, const char* attr_name, const TimeSettings& time) +{ + bool same_data = std::is_same::value; + + uint8_t attr_type = AI_TYPE_NONE; + if (std::is_same::value) + attr_type = AI_TYPE_FLOAT; + else if (std::is_same::value) + attr_type = AI_TYPE_INT; + else if (std::is_same::value) + attr_type = AI_TYPE_BOOLEAN; + else if (std::is_same::value) + attr_type = AI_TYPE_UINT; + else if (std::is_same::value) + attr_type = AI_TYPE_BYTE; + else if (std::is_same::value) + attr_type = AI_TYPE_VECTOR; + else if (std::is_same::value) + attr_type = AI_TYPE_RGB; + else if (std::is_same::value) + attr_type = AI_TYPE_RGBA; + else if (std::is_same::value) + attr_type = AI_TYPE_RGBA; + else if (std::is_same::value) + attr_type = AI_TYPE_STRING; + else if (std::is_same::value) + attr_type = AI_TYPE_STRING; + else if (std::is_same::value) + attr_type = AI_TYPE_MATRIX; + else if (std::is_same::value) { + if (std::is_same::value) // AtVector is represented the + // same way as GfVec3f + same_data = true; + attr_type = AI_TYPE_MATRIX; + } else if (std::is_same::value) { + attr_type = AI_TYPE_VECTOR; + if (std::is_same::value) // AtVector is represented the same + // way as GfVec3f + same_data = true; + } else if (std::is_same::value) + attr_type = AI_TYPE_VECTOR2; + else if (std::is_same::value) { + attr_type = AI_TYPE_VECTOR2; + if (std::is_same::value) // AtVector2 is represented the + // same way as GfVec2f + same_data = true; + } + + bool animated = time.motion_blur && attr.ValueMightBeTimeVarying(); + + if (!animated) { + // Single-key arrays + VtArray array; + if (!attr.Get(&array, time.frame)) + return 0; + + size_t size = array.size(); + if (size > 0) { + // The USD data representation is the same as the Arnold one, we don't + // need to convert the data + if (same_data) + AiNodeSetArray(node, attr_name, AiArrayConvert(size, 1, attr_type, array.cdata())); + else { + // Different data representation between USD and Arnold, we need to + // copy the vector. Note that we could instead allocate the AtArray + // and set the elements one by one, but I'm assuming it's faster + // this way + VtArray arnold_vec; + arnold_vec.assign(array.cbegin(), array.cend()); + AiNodeSetArray(node, attr_name, AiArrayConvert(size, 1, attr_type, arnold_vec.cdata())); + } + } else + AiNodeResetParameter(node, attr_name); + + return size; + } else { + // Animated array + GfInterval interval(time.start(), time.end(), false, false); + std::vector timeSamples; + attr.GetTimeSamplesInInterval(interval, &timeSamples); + size_t numKeys = AiMax(int(timeSamples.size()), (int)1); + numKeys += 2; // need to add the start end end keys (interval has open bounds) + + float timeStep = float(interval.GetMax() - interval.GetMin()) / int(numKeys - 1); + float timeVal = interval.GetMin(); + + VtArray array; + if (!attr.Get(&array, timeVal)) + return 0; + + size_t size = array.size(); + if (size == 0) { + AiNodeResetParameter(node, attr_name); + return 0; + } + VtArray arnold_vec; + arnold_vec.reserve(size * numKeys); + for (size_t i = 0; i < numKeys; i++, timeVal += timeStep) { + if (i > 0) { + if (!attr.Get(&array, timeVal)) { + return 0; + } + } + for (const auto& elem : array) { + arnold_vec.push_back(elem); + } + } + AiNodeSetArray(node, attr_name, AiArrayConvert(size, numKeys, attr_type, arnold_vec.data())); + return size; + } +} + +// Export a primvar +template +bool export_primvar( + const VtValue& vtValue, const VtIntArray& vtIndices, const TfToken& name, const SdfValueTypeName& typeName, + const TfToken& interpolation, const UsdPrim& prim, AtNode* node, MeshOrientation* orientation = NULL) +{ + if (!vtValue.IsHolding>()) + return false; + + TfToken arnoldName = name; + bool needDeclare = true; + + // Convert interpolation -> scope + // + // USD Interpolation determines how the Primvar interpolates over a + // geometric primitive: + // constant One value remains constant over the entire surface + // primitive. + // uniform One value remains constant for each uv patch segment of the + // surface primitive (which is a face for meshes). + // varying Four values are interpolated over each uv patch segment of + // the surface. Bilinear interpolation is used for interpolation + // between the four values. + // vertex Values are interpolated between each vertex in the surface + // primitive. The basis function of the surface is used for + // interpolation between vertices. + // faceVarying For polygons and subdivision surfaces, four values are + // interpolated over each face of the mesh. Bilinear + // interpolation is used for interpolation between the four + // values. + // + // There are four kinds of user-defined data in Arnold: + // + // constant constant parameters are data that are defined on a + // per-object basis and do not vary across the surface of that + // object. + // uniform uniform parameters are data that are defined on a "per-face" + // basis. During subdivision (if appropriate) values are not + // interpolated. Instead, the newly subdivided faces will + // contain the value of their "parent" face. + // varying varying parameters are data that are defined on a per-vertex + // basis. During subdivision (if appropriate), the values at the + // new vertices are interpolated from the values at the old + // vertices. The user should only create parameters of + // "interpolatable" variable types (such as floats, colors, + // etc.) + // indexed indexed parameters are data that are defined on a + // per-face-vertex basis. During subdivision (if appropriate), + // the values at the new vertices are interpolated from the + // values at the old vertices, preserving edges where values + // were not shared. The user should only create parameters of + // "interpolatable" variable types (such as floats, colors, + // etc.) + std::string declaration = + (interpolation == UsdGeomTokens->uniform) + ? "uniform " + : (interpolation == UsdGeomTokens->varying) + ? "varying " + : (interpolation == UsdGeomTokens->vertex) + ? "varying " + : (interpolation == UsdGeomTokens->faceVarying) ? "indexed " : "constant "; + + int arnoldAPIType; + if (std::is_same::value) { + declaration += "VECTOR2"; + arnoldAPIType = AI_TYPE_VECTOR2; + + // A special case for UVs. + if (name == "uv") { + arnoldName = TfToken("uvlist"); + needDeclare = false; + } + } else if (std::is_same::value) { + TfToken role = typeName.GetRole(); + if (role == SdfValueRoleNames->Color) { + declaration += "RGB"; + arnoldAPIType = AI_TYPE_RGB; + } else { + declaration += "VECTOR"; + arnoldAPIType = AI_TYPE_VECTOR; + } + } else if (std::is_same::value) { + declaration += "FLOAT"; + arnoldAPIType = AI_TYPE_FLOAT; + } else if (std::is_same::value) { + declaration += "INT"; + arnoldAPIType = AI_TYPE_INT; + } else { + // Not supported. + return false; + } + + // Declare a user-defined parameter. + if (needDeclare) { + AiNodeDeclare(node, arnoldName.GetText(), declaration.c_str()); + } + + // Constant USD attributs are provided as an array of one element. + if (interpolation == UsdGeomTokens->constant) { + if (std::is_same::value) { + VtArray vecArray = vtValue.Get>(); + GfVec3f value = vecArray[0]; + + TfToken role = typeName.GetRole(); + if (role == SdfValueRoleNames->Color) { + AiNodeSetRGB(node, arnoldName.GetText(), value[0], value[1], value[2]); + } else { + AiNodeSetVec(node, arnoldName.GetText(), value[0], value[1], value[2]); + } + } else if (std::is_same::value) { + auto vector = vtValue.Get>()[0]; + AiNodeSetVec2(node, arnoldName.GetText(), vector[0], vector[1]); + } else if (std::is_same::value) { + AiNodeSetFlt(node, arnoldName.GetText(), vtValue.Get>()[0]); + } else if (std::is_same::value) { + AiNodeSetInt(node, arnoldName.GetText(), vtValue.Get>()[0]); + } + } else { + const VtArray& rawVal = vtValue.Get>(); + AiNodeSetArray(node, arnoldName.GetText(), AiArrayConvert(rawVal.size(), 1, arnoldAPIType, rawVal.data())); + + if (interpolation == UsdGeomTokens->faceVarying) { + const std::string indexName = name.GetString() + "idxs"; + std::vector indexes; + + if (vtIndices.empty()) { + // Arnold doesn't have facevarying iterpolation. It has indexed + // instead. So it means it's necessary to generate indexes for + // this type. + // TODO: Try to generate indexes only once and use it for + // several primvars. + + indexes.resize(rawVal.size()); + // Fill it with 0, 1, ..., 99. + std::iota(std::begin(indexes), std::end(indexes), 0); + } else { + // We need to use indexes and we can't use vtIndices because we + // need unsigned int. Converting int to unsigned int. + indexes.resize(vtIndices.size()); + std::copy(vtIndices.begin(), vtIndices.end(), indexes.begin()); + } + + // If the mesh has left-handed orientation, we need to invert the + // indices of primvars for each face + if (orientation) + orientation->orient_face_index_attribute(indexes); + + AiNodeSetArray(node, indexName.c_str(), AiArrayConvert(indexes.size(), 1, AI_TYPE_UINT, indexes.data())); + } + } + return true; +} + +/** + * Export all primvars from this shape, and set them as arnold user data + * + **/ +void exportPrimvars(const UsdPrim& prim, AtNode* node, const TimeSettings& time, MeshOrientation* orientation = NULL); + +// Export the materials / shaders assigned to a shape (node) +void exportMaterialBinding(const UsdPrim& prim, AtNode* node, UsdArnoldReader& reader); + +/** + * Export a specific shader parameter from USD to Arnold + * + **/ +void exportParameter( + UsdShadeShader& shader, AtNode* node, const std::string& usdName, const std::string& arnoldName, + UsdArnoldReader& reader); + +AtNode* getNodeToConvert( + UsdArnoldReader& reader, const char* nodeType, const char* nodeName, bool create, bool convert); \ No newline at end of file diff --git a/translator/utils/utils.h b/translator/utils/utils.h new file mode 100755 index 0000000000..7095332cc6 --- /dev/null +++ b/translator/utils/utils.h @@ -0,0 +1,50 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include + +#include +#include +#include + +#include +#include + +PXR_NAMESPACE_USING_DIRECTIVE + +// convert from "snake_case" to "camelCase" +// ignores the capitalization of input strings: letters are only capitalized +// if they follow an underscore +// +inline std::string makeCamelCase(const std::string &in) +{ + std::string out; + out.reserve(in.length()); + bool capitalize = false; + unsigned char c; + for (size_t i = 0; i < in.length(); ++i) { + c = in[i]; + if (c == '_') { + capitalize = true; + } else { + if (capitalize) { + c = toupper(c); + capitalize = false; + } + out += c; + } + } + return out; +} diff --git a/translator/writer/prim_writer.cpp b/translator/writer/prim_writer.cpp new file mode 100755 index 0000000000..3e3083da44 --- /dev/null +++ b/translator/writer/prim_writer.cpp @@ -0,0 +1,430 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "prim_writer.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +//-************************************************************************* + +PXR_NAMESPACE_USING_DIRECTIVE + +namespace { +inline GfMatrix4d NodeGetGfMatrix(const AtNode* node, const char* param) +{ + const AtMatrix mat = AiNodeGetMatrix(node, param); + GfMatrix4f matFlt(mat.data); + return GfMatrix4d(matFlt); +}; + +inline const char* GetEnum(AtEnum en, int32_t id) +{ + if (en == nullptr) { + return ""; + } + if (id < 0) { + return ""; + } + for (auto i = 0; i <= id; ++i) { + if (en[i] == nullptr) { + return ""; + } + } + return en[id]; +} + +// Helper to convert parameters. It's a unordered_map having the attribute type +// as the key, and as value the USD attribute type, as well as the function +// doing the conversion. Note that this could be switched to a vector instead of +// a map for efficiency, but for now having it this way makes the code simpler +using ParamConversionMap = std::unordered_map; +const ParamConversionMap& _ParamConversionMap() +{ + static const ParamConversionMap ret = { + {AI_TYPE_BYTE, + {SdfValueTypeNames->UChar, + [](const AtNode* no, const char* na) -> VtValue { return VtValue(AiNodeGetByte(no, na)); }, + [](const AtNode* no, const char* na, const AtParamValue* pentry) -> bool { + return (pentry->BYTE() == AiNodeGetByte(no, na)); + }}}, + {AI_TYPE_INT, + {SdfValueTypeNames->Int, [](const AtNode* no, const char* na) -> VtValue { return VtValue(AiNodeGetInt(no, na)); }, + [](const AtNode* no, const char* na, const AtParamValue* pentry) -> bool { + return (pentry->INT() == AiNodeGetInt(no, na)); + }}}, + {AI_TYPE_UINT, + {SdfValueTypeNames->UInt, + [](const AtNode* no, const char* na) -> VtValue { return VtValue(AiNodeGetUInt(no, na)); }, + [](const AtNode* no, const char* na, const AtParamValue* pentry) -> bool { + return (pentry->UINT() == AiNodeGetUInt(no, na)); + }}}, + {AI_TYPE_BOOLEAN, + {SdfValueTypeNames->Bool, + [](const AtNode* no, const char* na) -> VtValue { return VtValue(AiNodeGetBool(no, na)); }, + [](const AtNode* no, const char* na, const AtParamValue* pentry) -> bool { + return (pentry->BOOL() == AiNodeGetBool(no, na)); + }}}, + {AI_TYPE_FLOAT, + {SdfValueTypeNames->Float, + [](const AtNode* no, const char* na) -> VtValue { return VtValue(AiNodeGetFlt(no, na)); }, + [](const AtNode* no, const char* na, const AtParamValue* pentry) -> bool { + return (pentry->FLT() == AiNodeGetFlt(no, na)); + }}}, + {AI_TYPE_RGB, + {SdfValueTypeNames->Color3f, + [](const AtNode* no, const char* na) -> VtValue { + const auto v = AiNodeGetRGB(no, na); + return VtValue(GfVec3f(v.r, v.g, v.b)); + }, + [](const AtNode* no, const char* na, const AtParamValue* pentry) -> bool { + return (pentry->RGB() == AiNodeGetRGB(no, na)); + }}}, + {AI_TYPE_RGBA, + {SdfValueTypeNames->Color4f, + [](const AtNode* no, const char* na) -> VtValue { + const auto v = AiNodeGetRGBA(no, na); + return VtValue(GfVec4f(v.r, v.g, v.b, v.a)); + }, + [](const AtNode* no, const char* na, const AtParamValue* pentry) -> bool { + return (pentry->RGBA() == AiNodeGetRGBA(no, na)); + }}}, + {AI_TYPE_VECTOR, + {SdfValueTypeNames->Vector3f, + [](const AtNode* no, const char* na) -> VtValue { + const auto v = AiNodeGetVec(no, na); + return VtValue(GfVec3f(v.x, v.y, v.z)); + }, + [](const AtNode* no, const char* na, const AtParamValue* pentry) -> bool { + return (pentry->VEC() == AiNodeGetVec(no, na)); + }}}, + {AI_TYPE_VECTOR2, + {SdfValueTypeNames->Float2, + [](const AtNode* no, const char* na) -> VtValue { + const auto v = AiNodeGetVec2(no, na); + return VtValue(GfVec2f(v.x, v.y)); + }, + [](const AtNode* no, const char* na, const AtParamValue* pentry) -> bool { + return (pentry->VEC2() == AiNodeGetVec2(no, na)); + }}}, + {AI_TYPE_STRING, + {SdfValueTypeNames->String, + [](const AtNode* no, const char* na) -> VtValue { return VtValue(AiNodeGetStr(no, na).c_str()); }, + [](const AtNode* no, const char* na, const AtParamValue* pentry) -> bool { + return (pentry->STR() == AiNodeGetStr(no, na)); + }}}, + {AI_TYPE_POINTER, {SdfValueTypeNames->String, nullptr, nullptr}}, + {AI_TYPE_NODE, + {SdfValueTypeNames->String, + [](const AtNode* no, const char* na) -> VtValue { + std::string targetName; + AtNode* target = (AtNode*)AiNodeGetPtr(no, na); + if (target) { + targetName = AiNodeGetName(target); + } + return VtValue(targetName); + }, + [](const AtNode* no, const char* na, const AtParamValue* pentry) -> bool { + return (AiNodeGetPtr(no, na) != nullptr); + }}}, + {AI_TYPE_MATRIX, + {SdfValueTypeNames->Matrix4d, + [](const AtNode* no, const char* na) -> VtValue { return VtValue(NodeGetGfMatrix(no, na)); }, + [](const AtNode* no, const char* na, const AtParamValue* pentry) -> bool { + return AiM4IsIdentity(AiNodeGetMatrix(no, na)); + }}}, + {AI_TYPE_ENUM, + {SdfValueTypeNames->String, + [](const AtNode* no, const char* na) -> VtValue { + const auto* nentry = AiNodeGetNodeEntry(no); + if (nentry == nullptr) { + return VtValue(""); + } + const auto* pentry = AiNodeEntryLookUpParameter(nentry, na); + if (pentry == nullptr) { + return VtValue(""); + } + const auto enums = AiParamGetEnum(pentry); + return VtValue(GetEnum(enums, AiNodeGetInt(no, na))); + }, + [](const AtNode* no, const char* na, const AtParamValue* pentry) -> bool { + return (pentry->INT() == AiNodeGetInt(no, na)); + }}}, + {AI_TYPE_CLOSURE, {SdfValueTypeNames->String, nullptr, nullptr}}, + {AI_TYPE_USHORT, + {SdfValueTypeNames->UInt, + [](const AtNode* no, const char* na) -> VtValue { return VtValue(AiNodeGetUInt(no, na)); }, + [](const AtNode* no, const char* na, const AtParamValue* pentry) -> bool { + return (pentry->UINT() == AiNodeGetUInt(no, na)); + }}}, + {AI_TYPE_HALF, + {SdfValueTypeNames->Half, + [](const AtNode* no, const char* na) -> VtValue { return VtValue(AiNodeGetFlt(no, na)); }, + [](const AtNode* no, const char* na, const AtParamValue* pentry) -> bool { + return (pentry->FLT() == AiNodeGetFlt(no, na)); + }}}}; + return ret; +} + +} // namespace + +// Get the conversion item for this node type (see above) +const UsdArnoldPrimWriter::ParamConversion* UsdArnoldPrimWriter::getParamConversion(uint8_t type) +{ + const auto it = _ParamConversionMap().find(type); + if (it != _ParamConversionMap().end()) { + return &it->second; + } else { + return nullptr; + } +} + +/** + * Get the USD node name for this Arnold node. We need to replace the + *forbidden characters from the names. Also, we must ensure that the first + *character is a slash + **/ +std::string UsdArnoldPrimWriter::GetArnoldNodeName(const AtNode* node) +{ + std::string name = AiNodeGetName(node); + if (name.empty()) { + return name; + } + + // We need to determine which parameters must be converted to underscores + // and which must be converted to slashes. In Maya node names, pipes + // correspond to hierarchies so for now I'm converting them to slashes. + std::replace(name.begin(), name.end(), '|', '/'); + std::replace(name.begin(), name.end(), '@', '_'); + std::replace(name.begin(), name.end(), '.', '_'); + std::replace(name.begin(), name.end(), ':', '_'); + + if (name[0] != '/') { + name = std::string("/") + name; + } + + return name; +} + +void UsdArnoldPrimWriter::writeArnoldParameters( + const AtNode* node, UsdArnoldWriter& writer, UsdPrim& prim, bool use_namespace) +{ + // Loop over the arnold parameters, and write them + const AtNodeEntry* nodeEntry = AiNodeGetNodeEntry(node); + AtParamIterator* paramIter = AiNodeEntryGetParamIterator(nodeEntry); + + while (!AiParamIteratorFinished(paramIter)) { + const AtParamEntry* paramEntry = AiParamIteratorGetNext(paramIter); + const char* paramName(AiParamGetName(paramEntry)); + if (strcmp(paramName, "name") == 0) { // "name" is an exception and shouldn't be saved + continue; + } + + int paramType = AiParamGetType(paramEntry); + // for now all attributes are in the "arnold:" namespace + std::string usdParamName = + (use_namespace) ? std::string("arnold:") + std::string(paramName) : std::string(paramName); + + if (paramType == AI_TYPE_ARRAY) { + AtArray* array = AiNodeGetArray(node, paramName); + if (array == nullptr) { + continue; + } + int arrayType = AiArrayGetType(array); + unsigned int arraySize = AiArrayGetNumElements(array); + if (arraySize == 0) { + continue; // no need to export empty arrays + } + + UsdAttribute attr; + SdfValueTypeName usdTypeName; + + switch (arrayType) { + { + case AI_TYPE_BYTE: + attr = prim.CreateAttribute(TfToken(usdParamName), SdfValueTypeNames->UCharArray, false); + VtArray vtArr(arraySize); + for (unsigned int i = 0; i < arraySize; ++i) { + vtArr[i] = AiArrayGetByte(array, i); + } + attr.Set(vtArr); + break; + } + { + case AI_TYPE_INT: + attr = prim.CreateAttribute(TfToken(usdParamName), SdfValueTypeNames->IntArray, false); + VtArray vtArr(arraySize); + for (unsigned int i = 0; i < arraySize; ++i) { + vtArr[i] = AiArrayGetInt(array, i); + } + attr.Set(vtArr); + break; + } + { + case AI_TYPE_UINT: + attr = prim.CreateAttribute(TfToken(usdParamName), SdfValueTypeNames->UIntArray, false); + VtArray vtArr(arraySize); + for (unsigned int i = 0; i < arraySize; ++i) { + vtArr[i] = AiArrayGetUInt(array, i); + } + attr.Set(vtArr); + break; + } + { + case AI_TYPE_BOOLEAN: + attr = prim.CreateAttribute(TfToken(usdParamName), SdfValueTypeNames->BoolArray, false); + VtArray vtArr(arraySize); + for (unsigned int i = 0; i < arraySize; ++i) { + vtArr[i] = AiArrayGetBool(array, i); + } + attr.Set(vtArr); + break; + } + { + case AI_TYPE_FLOAT: + attr = prim.CreateAttribute(TfToken(usdParamName), SdfValueTypeNames->FloatArray, false); + VtArray vtArr(arraySize); + for (unsigned int i = 0; i < arraySize; ++i) { + vtArr[i] = AiArrayGetFlt(array, i); + } + attr.Set(vtArr); + break; + } + { + case AI_TYPE_RGB: + attr = prim.CreateAttribute(TfToken(usdParamName), SdfValueTypeNames->Color3fArray, false); + VtArray vtArr(arraySize); + for (unsigned int i = 0; i < arraySize; ++i) { + AtRGB col = AiArrayGetRGB(array, i); + vtArr[i] = GfVec3f(col.r, col.g, col.b); + } + attr.Set(vtArr); + break; + } + { + case AI_TYPE_VECTOR: + attr = prim.CreateAttribute(TfToken(usdParamName), SdfValueTypeNames->Vector3fArray, false); + VtArray vtArr(arraySize); + for (unsigned int i = 0; i < arraySize; ++i) { + AtVector vec = AiArrayGetVec(array, i); + vtArr[i] = GfVec3f(vec.x, vec.y, vec.z); + } + attr.Set(vtArr); + break; + } + { + case AI_TYPE_RGBA: + attr = prim.CreateAttribute(TfToken(usdParamName), SdfValueTypeNames->Color4fArray, false); + VtArray vtArr(arraySize); + for (unsigned int i = 0; i < arraySize; ++i) { + AtRGBA col = AiArrayGetRGBA(array, i); + vtArr[i] = GfVec4f(col.r, col.g, col.b, col.a); + } + attr.Set(vtArr); + break; + } + { + case AI_TYPE_VECTOR2: + attr = prim.CreateAttribute(TfToken(usdParamName), SdfValueTypeNames->Float2Array, false); + VtArray vtArr(arraySize); + for (unsigned int i = 0; i < arraySize; ++i) { + AtVector2 vec = AiArrayGetVec2(array, i); + vtArr[i] = GfVec2f(vec.x, vec.y); + } + attr.Set(vtArr); + break; + } + { + case AI_TYPE_STRING: + attr = prim.CreateAttribute(TfToken(usdParamName), SdfValueTypeNames->StringArray, false); + VtArray vtArr(arraySize); + for (unsigned int i = 0; i < arraySize; ++i) { + AtString str = AiArrayGetStr(array, i); + vtArr[i] = str.c_str(); + } + attr.Set(vtArr); + break; + } + { + case AI_TYPE_MATRIX: + attr = prim.CreateAttribute(TfToken(usdParamName), SdfValueTypeNames->Matrix4dArray, false); + VtArray vtArr(arraySize); + for (unsigned int i = 0; i < arraySize; ++i) { + const AtMatrix mat = AiArrayGetMtx(array, i); + GfMatrix4f matFlt(mat.data); + vtArr[i] = GfMatrix4d(matFlt); + } + attr.Set(vtArr); + break; + } + { + case AI_TYPE_NODE: + // only export the first element for now + attr = prim.CreateAttribute(TfToken(usdParamName), SdfValueTypeNames->StringArray, false); + VtArray vtArr(arraySize); + for (unsigned int i = 0; i < arraySize; ++i) { + AtNode* target = (AtNode*)AiArrayGetPtr(array, i); + vtArr[i] = (target) ? AiNodeGetName(target) : ""; + } + attr.Set(vtArr); + } + } + } else { + const auto iterType = getParamConversion(paramType); + + bool isLinked = AiNodeIsLinked(node, paramName); + + if (!isLinked && iterType != nullptr && iterType->d(node, paramName, AiParamGetDefault(paramEntry))) { + continue; // default value, no need to write it + } + + UsdAttribute attr = prim.CreateAttribute(TfToken(usdParamName), iterType->type, false); + if (iterType != nullptr && iterType->f != nullptr) { + attr.Set(iterType->f(node, paramName)); + } + if (isLinked) { + AtNode* target = AiNodeGetLink(node, paramName); + if (target) { + writer.writePrimitive(target); + attr.AddConnection(SdfPath(GetArnoldNodeName(target))); + } + } + } + } + AiParamIteratorDestroy(paramIter); +} +//================= Unsupported primitives +/** + * This function will be invoked for node types that are explicitely not + *supported. We'll dump a warning, saying that this node isn't supported in the + *USD conversion + **/ +void UsdArnoldWriteUnsupported::write(const AtNode* node, UsdArnoldWriter& writer) +{ + if (node == NULL) { + return; + } + + AiMsgWarning("UsdArnoldWriter : %s nodes not supported, cannot write %s", _type.c_str(), AiNodeGetName(node)); +} diff --git a/translator/writer/prim_writer.h b/translator/writer/prim_writer.h new file mode 100755 index 0000000000..823b6f1d7c --- /dev/null +++ b/translator/writer/prim_writer.h @@ -0,0 +1,86 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "writer.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +/** + * Base Class for a UsdPrim writer. This class is in charge of converting + *Arnold primitives to USD + * + **/ +class UsdArnoldPrimWriter { +public: + UsdArnoldPrimWriter() {} + virtual ~UsdArnoldPrimWriter() {} + + virtual void write(const AtNode *node, UsdArnoldWriter &writer) = 0; + + // Helper structure to convert parameters + struct ParamConversion { + const SdfValueTypeName &type; + std::function f; + std::function d; + + ParamConversion( + const SdfValueTypeName &_type, std::function _f, + std::function _d) + : type(_type), f(std::move(_f)), d(std::move(_d)) + { + } + }; + + // get the proper conversion for the given arnold param type + static const ParamConversion *getParamConversion(uint8_t type); + // This function returns the name we want to give to this AtNode when it's + // converted to USD + static std::string GetArnoldNodeName(const AtNode *node); + +protected: + void writeArnoldParameters(const AtNode *node, UsdArnoldWriter &writer, UsdPrim &prim, bool use_namespace = true); +}; + +/** + * UsdArnoldWriteUnsupported is a prim writer for node types that aren't + *supported (yet). When trying to convert one of these nodes, an error message + *will appear + **/ +class UsdArnoldWriteUnsupported : public UsdArnoldPrimWriter { +public: + UsdArnoldWriteUnsupported(const std::string &type) : UsdArnoldPrimWriter(), _type(type) {} + void write(const AtNode *node, UsdArnoldWriter &writer) override; + +private: + std::string _type; +}; + +// Helper macro for prim writers +#define REGISTER_PRIM_WRITER(name) \ + class name : public UsdArnoldPrimWriter { \ + public: \ + void write(const AtNode *node, UsdArnoldWriter &writer) override; \ + }; diff --git a/translator/writer/registry.cpp b/translator/writer/registry.cpp new file mode 100755 index 0000000000..8bb7c6d784 --- /dev/null +++ b/translator/writer/registry.cpp @@ -0,0 +1,132 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "registry.h" + +#include + +#include "../utils/utils.h" +#include "write_arnold_type.h" +#include "write_shader.h" + +#include +#include +#include +#include + +//-************************************************************************* + +PXR_NAMESPACE_USING_DIRECTIVE + +// For now we're not registering any writer +UsdArnoldWriterRegistry::UsdArnoldWriterRegistry() +{ + // TODO: write to builtin USD types. For now we're creating these nodes as + // Arnold-Typed primitives at the end of this function + /* + // First, let's register all the prim writers that we've hardcoded for + USD builtin types registerWriter("polymesh", new UsdArnoldWriteMesh()); + registerWriter("curves", new UsdArnoldWriteCurves()); + registerWriter("points", new UsdArnoldWritePoints()); + registerWriter("box", new UsdArnoldWriteCube()); + registerWriter("sphere", new UsdArnoldWritephere()); + registerWriter("cylinder", new UsdArnoldWriteCylinder()); + registerWriter("cone", new UsdArnoldWriteCone()); + registerWriter("nurbs", new UsdArnoldWriteUnsupported("nurbs")); + + // Arnold nodes that can be exported as USD builtin Lights + registerWriter("distant_light", new UsdArnoldWriteDistantLight()); + registerWriter("skydome_light", new UsdArnoldWriteDomeLight()); + registerWriter("disk_light", new UsdArnoldWriteDiskLight()); + registerWriter("point_light", new UsdArnoldWriteSphereLight()); + registerWriter("quad_light", new UsdArnoldWriteRectLight()); + registerWriter("mesh_light", new UsdArnoldWriteGeometryLight()); + */ + + // Now let's iterate over all the arnold classes known at this point + bool universeCreated = false; + // If a universe is already active, we can just use it, otherwise we need to + // call AiBegin. + // But if we do so, we'll have to call AiEnd() when we finish + if (!AiUniverseIsActive()) { + AiBegin(); + universeCreated = true; + // FIXME: should we call AiLoadPlugins here ? + } + + // Iterate over all node types + AtNodeEntryIterator *nodeEntryIter = AiUniverseGetNodeEntryIterator(AI_NODE_ALL); + while (!AiNodeEntryIteratorFinished(nodeEntryIter)) { + AtNodeEntry *nodeEntry = AiNodeEntryIteratorGetNext(nodeEntryIter); + std::string entryName = AiNodeEntryGetName(nodeEntry); + + // if a primWriter is already registed for this AtNodeEntry (i.e. from + // the above list), then we should skip it. We want these nodes to be + // exported as USD native primitive + if (getPrimWriter(entryName)) { + continue; + } + + std::string entryTypeName = AiNodeEntryGetTypeName(nodeEntry); + + std::string usdName = makeCamelCase(entryName); + if (usdName.length() == 0) { + continue; + } + usdName[0] = toupper(usdName[0]); + usdName = std::string("Arnold") + usdName; + + /* + if (entryTypeName == "shader") { + // We want to export all shaders as a UsdShader primitive, + // and set the shader type in info:id + registerWriter( + entryName, new UsdArnoldWriteShader(entryName, usdName)); + } else */ + { + // Generic writer for arnold nodes. + registerWriter(entryName, new UsdArnoldWriteArnoldType(entryName, usdName, entryTypeName)); + } + } + AiNodeEntryIteratorDestroy(nodeEntryIter); + + if (universeCreated) { + AiEnd(); + } +} +UsdArnoldWriterRegistry::~UsdArnoldWriterRegistry() +{ + // Delete all the prim readers that were registed here + std::unordered_map::iterator it = _writersMap.begin(); + std::unordered_map::iterator itEnd = _writersMap.end(); + + for (; it != itEnd; ++it) { + delete it->second; + } +} + +/** + * Register a prim writer for a given Arnold node type, overriding the + *eventual existing one. + * + **/ +void UsdArnoldWriterRegistry::registerWriter(const std::string &primName, UsdArnoldPrimWriter *primWriter) +{ + std::unordered_map::iterator it = _writersMap.find(primName); + if (it != _writersMap.end()) { + // we have already registered a reader for this node type, let's delete + // the existing one and override it + delete it->second; + } + _writersMap[primName] = primWriter; +} diff --git a/translator/writer/registry.h b/translator/writer/registry.h new file mode 100755 index 0000000000..d2de1c458b --- /dev/null +++ b/translator/writer/registry.h @@ -0,0 +1,56 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include + +#include + +#include +#include +#include + +class UsdArnoldPrimWriter; + +PXR_NAMESPACE_USING_DIRECTIVE + +/** + * The Registry stores a map returning which prim writer should be used for a + *given Arnold node entry. It is similar to the "reader" registry. Node types + *that were not registered will be skipped from the export + **/ + +class UsdArnoldWriterRegistry { +public: + UsdArnoldWriterRegistry(); + virtual ~UsdArnoldWriterRegistry(); + + // Register a new prim writer to this type of usd primitive. + // If an existing one was previously registed for this same type, it will be + // deleted and overridden + void registerWriter(const std::string &primName, UsdArnoldPrimWriter *primWriter); + + UsdArnoldPrimWriter *getPrimWriter(const std::string &primName) + { + std::unordered_map::iterator it = _writersMap.find(primName); + if (it == _writersMap.end()) + return NULL; // return NULL if no writer was registered for this + // node type, it will be skipped + + return it->second; + } + +private: + std::unordered_map _writersMap; +}; diff --git a/translator/writer/write_arnold_type.cpp b/translator/writer/write_arnold_type.cpp new file mode 100755 index 0000000000..f632c1ec57 --- /dev/null +++ b/translator/writer/write_arnold_type.cpp @@ -0,0 +1,57 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "write_arnold_type.h" + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + +//-************************************************************************* + +PXR_NAMESPACE_USING_DIRECTIVE + +/** + * Write out any Arnold node to a generic "typed" USD primitive (eg + *ArnoldSetParameter, ArnoldDriverExr, etc...). In this write function, we need + *to create the USD primitive, then loop over the Arnold node attributes, and + *write them to the USD file. Note that we could (should) use the schemas to do + *this, but since the conversion is simple, for now we're hardcoding it here. + *For now the attributes are prefixed with "arnold:" as this is what is done in + *the schemas. But this is something that we could remove in the future, as it's + *not strictly needed. + **/ +void UsdArnoldWriteArnoldType::write(const AtNode *node, UsdArnoldWriter &writer) +{ + std::string nodeName = GetArnoldNodeName(node); // what should be the name of this USD primitive + UsdStageRefPtr stage = writer.getUsdStage(); // get the current stage defined in the writer + SdfPath objPath(nodeName); + + UsdPrim prim = stage->GetPrimAtPath(objPath); + if (prim && prim.IsActive()) { + // This primitive was already written, let's early out + return; + } + prim = stage->DefinePrim(objPath, TfToken(_usdName)); + + writeArnoldParameters(node, writer, prim); +} diff --git a/translator/writer/write_arnold_type.h b/translator/writer/write_arnold_type.h new file mode 100755 index 0000000000..6379d3141f --- /dev/null +++ b/translator/writer/write_arnold_type.h @@ -0,0 +1,47 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include + +#include + +#include +#include + +#include "prim_writer.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +/** + * Prim Writers for generic Arnold nodes. These nodes will be saved as + *"typed" schemas, with a node type prefixed with "Arnold", and camel-cased + *names. For example, set_parameter will be saved as a typed usd node + *"ArnoldSetParameter". For now the attribute are saved with the "arnold:" + *namespace, but this could be changed as the namespace isn't strictly needed on + *typed schemas + **/ +class UsdArnoldWriteArnoldType : public UsdArnoldPrimWriter { +public: + UsdArnoldWriteArnoldType(const std::string &entryName, const std::string &usdName, const std::string &entryTypeName) + : UsdArnoldPrimWriter(), _entryName(entryName), _usdName(usdName), _entryTypeName(entryTypeName) + { + } + void write(const AtNode *node, UsdArnoldWriter &writer) override; + +private: + std::string _entryName; + std::string _usdName; + std::string _entryTypeName; +}; diff --git a/translator/writer/write_shader.cpp b/translator/writer/write_shader.cpp new file mode 100755 index 0000000000..dc87252e64 --- /dev/null +++ b/translator/writer/write_shader.cpp @@ -0,0 +1,51 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "write_shader.h" + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "registry.h" + +//-************************************************************************* + +PXR_NAMESPACE_USING_DIRECTIVE + +/** + * Export Arnold shaders as UsdShadeShader primitives. The output primitive + *type is a generic "shader", and the actual shader name will be set in the + *"info:id" attribute. Input parameter are saved in the "input:" namespace. + **/ + +void UsdArnoldWriteShader::write(const AtNode *node, UsdArnoldWriter &writer) +{ + std::string nodeName = GetArnoldNodeName(node); // what is the USD name for this primitive + UsdStageRefPtr stage = writer.getUsdStage(); // Get the USD stage defined in the writer + + // Create the primitive of type Shader (UsdShadeShader) + UsdShadeShader shaderAPI = UsdShadeShader::Define(stage, SdfPath(nodeName)); + shaderAPI.CreateIdAttr().Set(TfToken(_usdShaderId)); // set the info:id parameter to the actual shader name + + UsdPrim prim = shaderAPI.GetPrim(); + writeArnoldParameters(node, writer, prim, true); +} diff --git a/translator/writer/write_shader.h b/translator/writer/write_shader.h new file mode 100755 index 0000000000..dd4784b868 --- /dev/null +++ b/translator/writer/write_shader.h @@ -0,0 +1,47 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include + +#include + +#include +#include +#include + +#include "prim_writer.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +/** + * The Shader Writer will be used to save an Arnold shader as a UsdShadeShader + *primitive. This is a generic "Shader" primitive in USD, that stores the name + *(id) of the shader in its attribute "info:id". Here all the shader names will + *be prefixed by "Arnold" in order to recognize them, and they will be + *camel-cased (standard_surface -> ArnoldStandardSurface). The input attributes + *are expected to be in the "input" scope (e.g. input:base_color, etc...) + **/ +class UsdArnoldWriteShader : public UsdArnoldPrimWriter { +public: + UsdArnoldWriteShader(const std::string &entryName, const std::string &usdShaderId) + : UsdArnoldPrimWriter(), _entryName(entryName), _usdShaderId(usdShaderId) + { + } + void write(const AtNode *node, UsdArnoldWriter &writer) override; + +private: + std::string _entryName; // node entry name for this node + std::string _usdShaderId; // name (id) of this shader in USD-land +}; diff --git a/translator/writer/writer.cpp b/translator/writer/writer.cpp new file mode 100755 index 0000000000..d6a84b06ea --- /dev/null +++ b/translator/writer/writer.cpp @@ -0,0 +1,88 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "writer.h" + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "prim_writer.h" +#include "registry.h" + +//-************************************************************************* + +PXR_NAMESPACE_USING_DIRECTIVE + +// global writer registry, will be used in the default case +static UsdArnoldWriterRegistry *s_writerRegistry = NULL; + +/** + * Write out a given Arnold universe to a USD stage + * + **/ +void UsdArnoldWriter::write(const AtUniverse *universe) +{ + _universe = universe; + // eventually use a dedicated registry + if (_registry == NULL) { + // No registry was set (default), let's use the global one + if (s_writerRegistry == NULL) { + s_writerRegistry = new UsdArnoldWriterRegistry(); // initialize the global registry + } + _registry = s_writerRegistry; + } + + // Loop over the universe nodes, and write each of them + AtNodeIterator *iter = AiUniverseGetNodeIterator(_universe, AI_NODE_ALL); + while (!AiNodeIteratorFinished(iter)) { + writePrimitive(AiNodeIteratorGetNext(iter)); + } + AiNodeIteratorDestroy(iter); + _universe = NULL; +} + +/** + * Write out the primitive, by using the registered primitive writer. + * + **/ +void UsdArnoldWriter::writePrimitive(const AtNode *node) +{ + if (node == NULL) { + return; + } + + std::string objName = AiNodeGetName(node); + + // some Arnold nodes shouldn't be saved + if (objName == "root" || objName == "ai_default_reflection_shader") { + return; + } + + std::string objType = AiNodeEntryGetName(AiNodeGetNodeEntry(node)); + + UsdArnoldPrimWriter *primWriter = _registry->getPrimWriter(objType); + if (primWriter) { + primWriter->write(node, *this); // write this primitive + } +} + +void UsdArnoldWriter::setRegistry(UsdArnoldWriterRegistry *registry) { _registry = registry; } diff --git a/translator/writer/writer.h b/translator/writer/writer.h new file mode 100755 index 0000000000..93f7e8f07a --- /dev/null +++ b/translator/writer/writer.h @@ -0,0 +1,54 @@ +// Copyright 2019 Autodesk, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include + +#include + +#include +#include + +PXR_NAMESPACE_USING_DIRECTIVE + +class UsdArnoldWriterRegistry; + +/** + * Class handling the translation of Arnold data to USD. + * A registry provides the desired primWriter for a given Arnold node entry + *name. + **/ + +class UsdArnoldWriter { +public: + UsdArnoldWriter() : _universe(NULL), _registry(NULL) {} + ~UsdArnoldWriter() {} + + void write(const AtUniverse *universe); // convert a given arnold universe + void writePrimitive(const AtNode *node); // write a primitive (node) + + void setRegistry(UsdArnoldWriterRegistry *registry); + + void setUsdStage(UsdStageRefPtr stage) { _stage = stage; } + const UsdStageRefPtr &getUsdStage() { return _stage; } + + void setUniverse(const AtUniverse *universe) { _universe = universe; } + const AtUniverse *getUniverse() const { return _universe; } + +private: + const AtUniverse *_universe; // Arnold universe to be converted + UsdArnoldWriterRegistry *_registry; // custom registry used for this writer. If null, a global + // registry will be used. + UsdStageRefPtr _stage; // USD stage where the primitives are added +};