10b57cec5SDimitry Andric //===- HeaderSearchOptions.h ------------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #ifndef LLVM_CLANG_LEX_HEADERSEARCHOPTIONS_H
100b57cec5SDimitry Andric #define LLVM_CLANG_LEX_HEADERSEARCHOPTIONS_H
110b57cec5SDimitry Andric 
120b57cec5SDimitry Andric #include "clang/Basic/LLVM.h"
130b57cec5SDimitry Andric #include "llvm/ADT/CachedHashString.h"
14a7dea167SDimitry Andric #include "llvm/ADT/Hashing.h"
150b57cec5SDimitry Andric #include "llvm/ADT/SetVector.h"
160b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
17349cc55cSDimitry Andric #include "llvm/Support/HashBuilder.h"
180b57cec5SDimitry Andric #include <cstdint>
19349cc55cSDimitry Andric #include <map>
200b57cec5SDimitry Andric #include <string>
210b57cec5SDimitry Andric #include <vector>
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric namespace clang {
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric namespace frontend {
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric /// IncludeDirGroup - Identifies the group an include Entry belongs to,
280b57cec5SDimitry Andric /// representing its relative positive in the search list.
290b57cec5SDimitry Andric /// \#include directives whose paths are enclosed by string quotes ("")
300b57cec5SDimitry Andric /// start searching at the Quoted group (specified by '-iquote'),
310b57cec5SDimitry Andric /// then search the Angled group, then the System group, etc.
320b57cec5SDimitry Andric enum IncludeDirGroup {
330b57cec5SDimitry Andric   /// '\#include ""' paths, added by 'gcc -iquote'.
340b57cec5SDimitry Andric   Quoted = 0,
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric   /// Paths for '\#include <>' added by '-I'.
370b57cec5SDimitry Andric   Angled,
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric   /// Like Angled, but marks header maps used when building frameworks.
400b57cec5SDimitry Andric   IndexHeaderMap,
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric   /// Like Angled, but marks system directories.
430b57cec5SDimitry Andric   System,
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric   /// Like System, but headers are implicitly wrapped in extern "C".
460b57cec5SDimitry Andric   ExternCSystem,
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric   /// Like System, but only used for C.
490b57cec5SDimitry Andric   CSystem,
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric   /// Like System, but only used for C++.
520b57cec5SDimitry Andric   CXXSystem,
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric   /// Like System, but only used for ObjC.
550b57cec5SDimitry Andric   ObjCSystem,
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric   /// Like System, but only used for ObjC++.
580b57cec5SDimitry Andric   ObjCXXSystem,
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric   /// Like System, but searched after the system directories.
610b57cec5SDimitry Andric   After
620b57cec5SDimitry Andric };
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric } // namespace frontend
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric /// HeaderSearchOptions - Helper class for storing options related to the
670b57cec5SDimitry Andric /// initialization of the HeaderSearch object.
680b57cec5SDimitry Andric class HeaderSearchOptions {
690b57cec5SDimitry Andric public:
700b57cec5SDimitry Andric   struct Entry {
710b57cec5SDimitry Andric     std::string Path;
720b57cec5SDimitry Andric     frontend::IncludeDirGroup Group;
735f757f3fSDimitry Andric     LLVM_PREFERRED_TYPE(bool)
740b57cec5SDimitry Andric     unsigned IsFramework : 1;
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric     /// IgnoreSysRoot - This is false if an absolute path should be treated
770b57cec5SDimitry Andric     /// relative to the sysroot, or true if it should always be the absolute
780b57cec5SDimitry Andric     /// path.
795f757f3fSDimitry Andric     LLVM_PREFERRED_TYPE(bool)
800b57cec5SDimitry Andric     unsigned IgnoreSysRoot : 1;
810b57cec5SDimitry Andric 
EntryEntry820b57cec5SDimitry Andric     Entry(StringRef path, frontend::IncludeDirGroup group, bool isFramework,
830b57cec5SDimitry Andric           bool ignoreSysRoot)
840b57cec5SDimitry Andric         : Path(path), Group(group), IsFramework(isFramework),
850b57cec5SDimitry Andric           IgnoreSysRoot(ignoreSysRoot) {}
860b57cec5SDimitry Andric   };
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric   struct SystemHeaderPrefix {
890b57cec5SDimitry Andric     /// A prefix to be matched against paths in \#include directives.
900b57cec5SDimitry Andric     std::string Prefix;
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric     /// True if paths beginning with this prefix should be treated as system
930b57cec5SDimitry Andric     /// headers.
940b57cec5SDimitry Andric     bool IsSystemHeader;
950b57cec5SDimitry Andric 
SystemHeaderPrefixSystemHeaderPrefix960b57cec5SDimitry Andric     SystemHeaderPrefix(StringRef Prefix, bool IsSystemHeader)
970b57cec5SDimitry Andric         : Prefix(Prefix), IsSystemHeader(IsSystemHeader) {}
980b57cec5SDimitry Andric   };
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric   /// If non-empty, the directory to use as a "virtual system root" for include
1010b57cec5SDimitry Andric   /// paths.
1020b57cec5SDimitry Andric   std::string Sysroot;
1030b57cec5SDimitry Andric 
1040b57cec5SDimitry Andric   /// User specified include entries.
1050b57cec5SDimitry Andric   std::vector<Entry> UserEntries;
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric   /// User-specified system header prefixes.
1080b57cec5SDimitry Andric   std::vector<SystemHeaderPrefix> SystemHeaderPrefixes;
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric   /// The directory which holds the compiler resource files (builtin includes,
1110b57cec5SDimitry Andric   /// etc.).
1120b57cec5SDimitry Andric   std::string ResourceDir;
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric   /// The directory used for the module cache.
1150b57cec5SDimitry Andric   std::string ModuleCachePath;
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric   /// The directory used for a user build.
1180b57cec5SDimitry Andric   std::string ModuleUserBuildPath;
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric   /// The mapping of module names to prebuilt module files.
1215ffd83dbSDimitry Andric   std::map<std::string, std::string, std::less<>> PrebuiltModuleFiles;
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric   /// The directories used to load prebuilt module files.
1240b57cec5SDimitry Andric   std::vector<std::string> PrebuiltModulePaths;
1250b57cec5SDimitry Andric 
1260b57cec5SDimitry Andric   /// The module/pch container format.
1270b57cec5SDimitry Andric   std::string ModuleFormat;
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric   /// Whether we should disable the use of the hash string within the
1300b57cec5SDimitry Andric   /// module cache.
1310b57cec5SDimitry Andric   ///
1320b57cec5SDimitry Andric   /// Note: Only used for testing!
1335f757f3fSDimitry Andric   LLVM_PREFERRED_TYPE(bool)
1340b57cec5SDimitry Andric   unsigned DisableModuleHash : 1;
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric   /// Implicit module maps.  This option is enabld by default when
1370b57cec5SDimitry Andric   /// modules is enabled.
1385f757f3fSDimitry Andric   LLVM_PREFERRED_TYPE(bool)
1390b57cec5SDimitry Andric   unsigned ImplicitModuleMaps : 1;
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric   /// Set the 'home directory' of a module map file to the current
1420b57cec5SDimitry Andric   /// working directory (or the home directory of the module map file that
1430b57cec5SDimitry Andric   /// contained the 'extern module' directive importing this module map file
1440b57cec5SDimitry Andric   /// if any) rather than the directory containing the module map file.
1450b57cec5SDimitry Andric   //
1460b57cec5SDimitry Andric   /// The home directory is where we look for files named in the module map
1470b57cec5SDimitry Andric   /// file.
1485f757f3fSDimitry Andric   LLVM_PREFERRED_TYPE(bool)
1490b57cec5SDimitry Andric   unsigned ModuleMapFileHomeIsCwd : 1;
1500b57cec5SDimitry Andric 
15181ad6265SDimitry Andric   /// Set the base path of a built module file to be the current working
15281ad6265SDimitry Andric   /// directory. This is useful for sharing module files across machines
15381ad6265SDimitry Andric   /// that build with different paths without having to rewrite all
15481ad6265SDimitry Andric   /// modulemap files to have working directory relative paths.
1555f757f3fSDimitry Andric   LLVM_PREFERRED_TYPE(bool)
15681ad6265SDimitry Andric   unsigned ModuleFileHomeIsCwd : 1;
15781ad6265SDimitry Andric 
158e8d8bef9SDimitry Andric   /// Also search for prebuilt implicit modules in the prebuilt module cache
159e8d8bef9SDimitry Andric   /// path.
1605f757f3fSDimitry Andric   LLVM_PREFERRED_TYPE(bool)
161e8d8bef9SDimitry Andric   unsigned EnablePrebuiltImplicitModules : 1;
162e8d8bef9SDimitry Andric 
1630b57cec5SDimitry Andric   /// The interval (in seconds) between pruning operations.
1640b57cec5SDimitry Andric   ///
1650b57cec5SDimitry Andric   /// This operation is expensive, because it requires Clang to walk through
1660b57cec5SDimitry Andric   /// the directory structure of the module cache, stat()'ing and removing
1670b57cec5SDimitry Andric   /// files.
1680b57cec5SDimitry Andric   ///
1690b57cec5SDimitry Andric   /// The default value is large, e.g., the operation runs once a week.
1700b57cec5SDimitry Andric   unsigned ModuleCachePruneInterval = 7 * 24 * 60 * 60;
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric   /// The time (in seconds) after which an unused module file will be
1730b57cec5SDimitry Andric   /// considered unused and will, therefore, be pruned.
1740b57cec5SDimitry Andric   ///
1750b57cec5SDimitry Andric   /// When the module cache is pruned, any module file that has not been
1760b57cec5SDimitry Andric   /// accessed in this many seconds will be removed. The default value is
1770b57cec5SDimitry Andric   /// large, e.g., a month, to avoid forcing infrequently-used modules to be
1780b57cec5SDimitry Andric   /// regenerated often.
1790b57cec5SDimitry Andric   unsigned ModuleCachePruneAfter = 31 * 24 * 60 * 60;
1800b57cec5SDimitry Andric 
1810b57cec5SDimitry Andric   /// The time in seconds when the build session started.
1820b57cec5SDimitry Andric   ///
1830b57cec5SDimitry Andric   /// This time is used by other optimizations in header search and module
1840b57cec5SDimitry Andric   /// loading.
1850b57cec5SDimitry Andric   uint64_t BuildSessionTimestamp = 0;
1860b57cec5SDimitry Andric 
1870b57cec5SDimitry Andric   /// The set of macro names that should be ignored for the purposes
1880b57cec5SDimitry Andric   /// of computing the module hash.
1890b57cec5SDimitry Andric   llvm::SmallSetVector<llvm::CachedHashString, 16> ModulesIgnoreMacros;
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric   /// The set of user-provided virtual filesystem overlay files.
1920b57cec5SDimitry Andric   std::vector<std::string> VFSOverlayFiles;
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric   /// Include the compiler builtin includes.
1955f757f3fSDimitry Andric   LLVM_PREFERRED_TYPE(bool)
1960b57cec5SDimitry Andric   unsigned UseBuiltinIncludes : 1;
1970b57cec5SDimitry Andric 
1980b57cec5SDimitry Andric   /// Include the system standard include search directories.
1995f757f3fSDimitry Andric   LLVM_PREFERRED_TYPE(bool)
2000b57cec5SDimitry Andric   unsigned UseStandardSystemIncludes : 1;
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric   /// Include the system standard C++ library include search directories.
2035f757f3fSDimitry Andric   LLVM_PREFERRED_TYPE(bool)
2040b57cec5SDimitry Andric   unsigned UseStandardCXXIncludes : 1;
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric   /// Use libc++ instead of the default libstdc++.
2075f757f3fSDimitry Andric   LLVM_PREFERRED_TYPE(bool)
2080b57cec5SDimitry Andric   unsigned UseLibcxx : 1;
2090b57cec5SDimitry Andric 
2100b57cec5SDimitry Andric   /// Whether header search information should be output as for -v.
2115f757f3fSDimitry Andric   LLVM_PREFERRED_TYPE(bool)
2120b57cec5SDimitry Andric   unsigned Verbose : 1;
2130b57cec5SDimitry Andric 
2140b57cec5SDimitry Andric   /// If true, skip verifying input files used by modules if the
2150b57cec5SDimitry Andric   /// module was already verified during this build session (see
2160b57cec5SDimitry Andric   /// \c BuildSessionTimestamp).
2175f757f3fSDimitry Andric   LLVM_PREFERRED_TYPE(bool)
2180b57cec5SDimitry Andric   unsigned ModulesValidateOncePerBuildSession : 1;
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric   /// Whether to validate system input files when a module is loaded.
2215f757f3fSDimitry Andric   LLVM_PREFERRED_TYPE(bool)
2220b57cec5SDimitry Andric   unsigned ModulesValidateSystemHeaders : 1;
2230b57cec5SDimitry Andric 
224a7dea167SDimitry Andric   // Whether the content of input files should be hashed and used to
225a7dea167SDimitry Andric   // validate consistency.
2265f757f3fSDimitry Andric   LLVM_PREFERRED_TYPE(bool)
227a7dea167SDimitry Andric   unsigned ValidateASTInputFilesContent : 1;
228a7dea167SDimitry Andric 
2295f757f3fSDimitry Andric   // Whether the input files from C++20 Modules should be checked.
2305f757f3fSDimitry Andric   LLVM_PREFERRED_TYPE(bool)
2315f757f3fSDimitry Andric   unsigned ForceCheckCXX20ModulesInputFiles : 1;
2325f757f3fSDimitry Andric 
2330b57cec5SDimitry Andric   /// Whether the module includes debug information (-gmodules).
2345f757f3fSDimitry Andric   LLVM_PREFERRED_TYPE(bool)
2350b57cec5SDimitry Andric   unsigned UseDebugInfo : 1;
2360b57cec5SDimitry Andric 
2375f757f3fSDimitry Andric   LLVM_PREFERRED_TYPE(bool)
2380b57cec5SDimitry Andric   unsigned ModulesValidateDiagnosticOptions : 1;
2390b57cec5SDimitry Andric 
2405f757f3fSDimitry Andric   /// Whether to entirely skip writing diagnostic options.
2415f757f3fSDimitry Andric   /// Primarily used to speed up deserialization during dependency scanning.
2425f757f3fSDimitry Andric   LLVM_PREFERRED_TYPE(bool)
2435f757f3fSDimitry Andric   unsigned ModulesSkipDiagnosticOptions : 1;
2445f757f3fSDimitry Andric 
2455f757f3fSDimitry Andric   /// Whether to entirely skip writing header search paths.
2465f757f3fSDimitry Andric   /// Primarily used to speed up deserialization during dependency scanning.
2475f757f3fSDimitry Andric   LLVM_PREFERRED_TYPE(bool)
2485f757f3fSDimitry Andric   unsigned ModulesSkipHeaderSearchPaths : 1;
2495f757f3fSDimitry Andric 
2505f757f3fSDimitry Andric   /// Whether to entirely skip writing pragma diagnostic mappings.
2515f757f3fSDimitry Andric   /// Primarily used to speed up deserialization during dependency scanning.
2525f757f3fSDimitry Andric   LLVM_PREFERRED_TYPE(bool)
2535f757f3fSDimitry Andric   unsigned ModulesSkipPragmaDiagnosticMappings : 1;
2545f757f3fSDimitry Andric 
2555f757f3fSDimitry Andric   LLVM_PREFERRED_TYPE(bool)
2560b57cec5SDimitry Andric   unsigned ModulesHashContent : 1;
2570b57cec5SDimitry Andric 
258a7dea167SDimitry Andric   /// Whether we should include all things that could impact the module in the
259a7dea167SDimitry Andric   /// hash.
260a7dea167SDimitry Andric   ///
261a7dea167SDimitry Andric   /// This includes things like the full header search path, and enabled
262a7dea167SDimitry Andric   /// diagnostics.
2635f757f3fSDimitry Andric   LLVM_PREFERRED_TYPE(bool)
264a7dea167SDimitry Andric   unsigned ModulesStrictContextHash : 1;
265a7dea167SDimitry Andric 
2660b57cec5SDimitry Andric   HeaderSearchOptions(StringRef _Sysroot = "/")
Sysroot(_Sysroot)2670b57cec5SDimitry Andric       : Sysroot(_Sysroot), ModuleFormat("raw"), DisableModuleHash(false),
2680b57cec5SDimitry Andric         ImplicitModuleMaps(false), ModuleMapFileHomeIsCwd(false),
26981ad6265SDimitry Andric         ModuleFileHomeIsCwd(false), EnablePrebuiltImplicitModules(false),
27081ad6265SDimitry Andric         UseBuiltinIncludes(true), UseStandardSystemIncludes(true),
27181ad6265SDimitry Andric         UseStandardCXXIncludes(true), UseLibcxx(false), Verbose(false),
2720b57cec5SDimitry Andric         ModulesValidateOncePerBuildSession(false),
273a7dea167SDimitry Andric         ModulesValidateSystemHeaders(false),
2745f757f3fSDimitry Andric         ValidateASTInputFilesContent(false),
2755f757f3fSDimitry Andric         ForceCheckCXX20ModulesInputFiles(false), UseDebugInfo(false),
2765f757f3fSDimitry Andric         ModulesValidateDiagnosticOptions(true),
2775f757f3fSDimitry Andric         ModulesSkipDiagnosticOptions(false),
2785f757f3fSDimitry Andric         ModulesSkipHeaderSearchPaths(false),
2795f757f3fSDimitry Andric         ModulesSkipPragmaDiagnosticMappings(false), ModulesHashContent(false),
280a7dea167SDimitry Andric         ModulesStrictContextHash(false) {}
2810b57cec5SDimitry Andric 
2820b57cec5SDimitry Andric   /// AddPath - Add the \p Path path to the specified \p Group list.
AddPath(StringRef Path,frontend::IncludeDirGroup Group,bool IsFramework,bool IgnoreSysRoot)2830b57cec5SDimitry Andric   void AddPath(StringRef Path, frontend::IncludeDirGroup Group,
2840b57cec5SDimitry Andric                bool IsFramework, bool IgnoreSysRoot) {
2850b57cec5SDimitry Andric     UserEntries.emplace_back(Path, Group, IsFramework, IgnoreSysRoot);
2860b57cec5SDimitry Andric   }
2870b57cec5SDimitry Andric 
2880b57cec5SDimitry Andric   /// AddSystemHeaderPrefix - Override whether \#include directives naming a
2890b57cec5SDimitry Andric   /// path starting with \p Prefix should be considered as naming a system
2900b57cec5SDimitry Andric   /// header.
AddSystemHeaderPrefix(StringRef Prefix,bool IsSystemHeader)2910b57cec5SDimitry Andric   void AddSystemHeaderPrefix(StringRef Prefix, bool IsSystemHeader) {
2920b57cec5SDimitry Andric     SystemHeaderPrefixes.emplace_back(Prefix, IsSystemHeader);
2930b57cec5SDimitry Andric   }
2940b57cec5SDimitry Andric 
AddVFSOverlayFile(StringRef Name)2950b57cec5SDimitry Andric   void AddVFSOverlayFile(StringRef Name) {
2965ffd83dbSDimitry Andric     VFSOverlayFiles.push_back(std::string(Name));
2970b57cec5SDimitry Andric   }
2980b57cec5SDimitry Andric 
AddPrebuiltModulePath(StringRef Name)2990b57cec5SDimitry Andric   void AddPrebuiltModulePath(StringRef Name) {
3005ffd83dbSDimitry Andric     PrebuiltModulePaths.push_back(std::string(Name));
3010b57cec5SDimitry Andric   }
3020b57cec5SDimitry Andric };
3030b57cec5SDimitry Andric 
hash_value(const HeaderSearchOptions::Entry & E)304a7dea167SDimitry Andric inline llvm::hash_code hash_value(const HeaderSearchOptions::Entry &E) {
305a7dea167SDimitry Andric   return llvm::hash_combine(E.Path, E.Group, E.IsFramework, E.IgnoreSysRoot);
306a7dea167SDimitry Andric }
307a7dea167SDimitry Andric 
3085f757f3fSDimitry Andric template <typename HasherT, llvm::endianness Endianness>
addHash(llvm::HashBuilder<HasherT,Endianness> & HBuilder,const HeaderSearchOptions::Entry & E)3095f757f3fSDimitry Andric inline void addHash(llvm::HashBuilder<HasherT, Endianness> &HBuilder,
310349cc55cSDimitry Andric                     const HeaderSearchOptions::Entry &E) {
311349cc55cSDimitry Andric   HBuilder.add(E.Path, E.Group, E.IsFramework, E.IgnoreSysRoot);
312349cc55cSDimitry Andric }
313349cc55cSDimitry Andric 
314a7dea167SDimitry Andric inline llvm::hash_code
hash_value(const HeaderSearchOptions::SystemHeaderPrefix & SHP)315a7dea167SDimitry Andric hash_value(const HeaderSearchOptions::SystemHeaderPrefix &SHP) {
316a7dea167SDimitry Andric   return llvm::hash_combine(SHP.Prefix, SHP.IsSystemHeader);
317a7dea167SDimitry Andric }
318a7dea167SDimitry Andric 
3195f757f3fSDimitry Andric template <typename HasherT, llvm::endianness Endianness>
addHash(llvm::HashBuilder<HasherT,Endianness> & HBuilder,const HeaderSearchOptions::SystemHeaderPrefix & SHP)3205f757f3fSDimitry Andric inline void addHash(llvm::HashBuilder<HasherT, Endianness> &HBuilder,
321349cc55cSDimitry Andric                     const HeaderSearchOptions::SystemHeaderPrefix &SHP) {
322349cc55cSDimitry Andric   HBuilder.add(SHP.Prefix, SHP.IsSystemHeader);
323349cc55cSDimitry Andric }
324349cc55cSDimitry Andric 
3250b57cec5SDimitry Andric } // namespace clang
3260b57cec5SDimitry Andric 
3270b57cec5SDimitry Andric #endif // LLVM_CLANG_LEX_HEADERSEARCHOPTIONS_H
328