1 // 2 // Copyright 2016 Pixar 3 // 4 // Licensed under the Apache License, Version 2.0 (the "Apache License") 5 // with the following modification; you may not use this file except in 6 // compliance with the Apache License and the following modification to it: 7 // Section 6. Trademarks. is deleted and replaced with: 8 // 9 // 6. Trademarks. This License does not grant permission to use the trade 10 // names, trademarks, service marks, or product names of the Licensor 11 // and its affiliates, except as required to comply with Section 4(c) of 12 // the License and to reproduce the content of the NOTICE file. 13 // 14 // You may obtain a copy of the Apache License at 15 // 16 // http://www.apache.org/licenses/LICENSE-2.0 17 // 18 // Unless required by applicable law or agreed to in writing, software 19 // distributed under the Apache License with the above modification is 20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 21 // KIND, either express or implied. See the Apache License for the specific 22 // language governing permissions and limitations under the Apache License. 23 // 24 #ifndef PXR_BASE_TF_ENV_SETTING_H 25 #define PXR_BASE_TF_ENV_SETTING_H 26 27 /// \file tf/envSetting.h 28 /// Environment setting variable. 29 /// 30 /// A \c TfEnvSetting<T> is used to access an environment variable that 31 /// controls program execution according to the value set in the environment. 32 /// Currently, the legal types for T are bool, int, and string. 33 /// 34 /// The TfEnvSetting facility is used to enable new features in the code that 35 /// are still in "experimental" mode, and warn the user and/or QA that they 36 /// are pushing the edge of the envelope by setting a non-standard value for 37 /// these variables. Accordingly, the \c TfEnvSetting construct should be 38 /// used as sparingly as possible in code. 39 /// 40 /// In contrast, a variable that allows the user to customize program 41 /// execution but is not an in-development code path should simply use 42 /// TfGetenv() to access the variable. An example would be supplying a 43 /// variable to override a default font or fontsize, for users who don't like 44 /// the default program choice (and when there is no other way to set the 45 /// preference). 46 /// 47 /// Here is how to use the TfEnvSetting facility. 48 /// 49 /// 1. First, define your variable in a single .cpp file: 50 /// 51 /// \code 52 /// #include "pxr/base/tf/envSetting.h" 53 /// 54 /// TF_DEFINE_ENV_SETTING(TDS_FILE_VERSION, 12, 55 /// "Default file format to use"); 56 /// \endcode 57 /// 58 /// The first argument is the name of your variable; it is also the name for 59 /// the variable you can set in your shell to set the value at runtime. The 60 /// second argument is the default value. To create a bool variable, pass 61 /// either true or false. To create a string variable, pass an explicit 62 /// string(), i.e. 63 /// 64 /// \code 65 /// TF_DEFINE_ENV_SETTING(TDS_FILE_SUFFIX, string(".tid"), 66 /// "Default file-name suffix"); 67 /// \endcode 68 /// 69 /// 2. If you need to access this variable outside the .cpp file that defines 70 /// the variable, put the following in a common header file: 71 /// 72 /// \code 73 /// extern TfEnvSetting<int> TDS_FILE_VERSION; 74 /// extern TfEnvSetting<string> TDS_FILE_SUFFIX; 75 /// \endcode 76 /// 77 /// 3. At runtime, access your variable using TfGetEnvSetting(). For example: 78 /// 79 /// \code 80 /// int version = TfGetEnvSetting(TDS_FILE_VERSION); 81 /// string const& suffix =TfGetEnvSetting(TDS_FILE_SUFFIX); 82 /// \endcode 83 /// 84 /// You can also access a variable's value from Python: 85 /// 86 /// \code{.py} 87 /// from pxr import Tf 88 /// suffix = Tf.GetEnvSetting("TDS_FILE_SUFFIX") 89 /// \endcode 90 /// 91 /// \c Tf.GetEnvSetting() returns the value for the TfEnvSetting variable, or 92 /// None if no such variable is defined in the currently loaded C++ code. 93 /// 94 /// If a user's environment has a value for a TfEnvSetting variable that 95 /// differs from the default, when the program starts or the module defining 96 /// the TfEnvSetting variable is loaded, a warning messages is printed. 97 /// 98 /// Additionally, at program startup time (or when lib/tf is first loaded), 99 /// the environment variable PIXAR_TF_ENV_SETTING_FILE is examined. If this 100 /// variable indicates a file that can be read, then the file is parsed, and 101 /// should contain lines of the form key=value. For each line read, the 102 /// environment variable key is set to value. For example: 103 /// 104 /// \code{.sh} 105 /// $ setenv PIXAR_TF_ENV_SETTING_FILE /usr/anim/<UNIT>/admin/env-settings 106 /// 107 /// $ cat /usr/anim/<UNIT>/admin/env-settings 108 /// TDS_DEF_VERSION=30 109 /// TDS_BLAH= 110 /// TDS_LONG_STRING=i am some long string with spaces 111 /// \endcode 112 /// 113 /// Blank lines in the file and lines where the first character is '#' are 114 /// ignored. If the file itself cannot be read, no error is printed; however, 115 /// if the file is malformed, errors are printed to stderr. 116 117 #include "pxr/pxr.h" 118 #include "pxr/base/arch/hints.h" 119 #include "pxr/base/tf/registryManager.h" 120 121 #include <atomic> 122 #include <string> 123 124 PXR_NAMESPACE_OPEN_SCOPE 125 126 // POD, statically initialized. 127 // 128 // We store the atomic_value separately and refer to it via pointer because we 129 // cannot use aggregate-initialization on a struct holding an atomic, but we 130 // can value-initialize a single std::atomic. 131 template <class T> 132 struct TfEnvSetting 133 { 134 std::atomic<T*> *_value; 135 T _default; 136 char const * _name; 137 char const * _description; 138 }; 139 140 // Specialize for string, default is stored as char const * (pointing to a 141 // literal). 142 template <> 143 struct TfEnvSetting<std::string> 144 { 145 std::atomic<std::string*> *_value; 146 char const * _default; 147 char const * _name; 148 char const * _description; 149 }; 150 151 template <class T> 152 void Tf_InitializeEnvSetting(TfEnvSetting<T> *); 153 154 /// Returns the value of the specified env setting, registered using 155 /// \c TF_DEFINE_ENV_SETTING. 156 template <class T> 157 inline T const & 158 TfGetEnvSetting(TfEnvSetting<T>& setting) { 159 extern void Tf_InitEnvSettings(); 160 Tf_InitEnvSettings(); 161 162 T *val = setting._value->load(); 163 if (ARCH_UNLIKELY(!val)) { 164 Tf_InitializeEnvSetting(&setting); 165 val = setting._value->load(); 166 } 167 return *val; 168 } 169 170 // Ensure that we only allow bool, int, and string, and map char * and char 171 // array to string. 172 173 bool Tf_ChooseEnvSettingType(bool); 174 int Tf_ChooseEnvSettingType(int); 175 std::string Tf_ChooseEnvSettingType(char const *); 176 177 class Tf_EnvSettingRegistry; 178 179 /// Define an env setting named \p envVar with default value \p defValue and a 180 /// descriptive string \p description. 181 /// \hideinitializer 182 #define TF_DEFINE_ENV_SETTING(envVar, defValue, description) \ 183 std::atomic< decltype(Tf_ChooseEnvSettingType(defValue))*> \ 184 envVar##_value; \ 185 TfEnvSetting<decltype(Tf_ChooseEnvSettingType(defValue))> envVar = { \ 186 &envVar##_value, defValue, #envVar, description }; \ 187 TF_REGISTRY_FUNCTION_WITH_TAG(Tf_EnvSettingRegistry, envVar) { \ 188 (void)TfGetEnvSetting(envVar); \ 189 } 190 191 PXR_NAMESPACE_CLOSE_SCOPE 192 193 #endif // PXR_BASE_TF_ENV_SETTING_H 194