Index: lldb/trunk/include/lldb/Core/ModuleList.h =================================================================== --- lldb/trunk/include/lldb/Core/ModuleList.h +++ lldb/trunk/include/lldb/Core/ModuleList.h @@ -12,6 +12,7 @@ #include "lldb/Core/Address.h" // for Address #include "lldb/Core/ModuleSpec.h" // for ModuleSpec +#include "lldb/Core/UserSettingsController.h" #include "lldb/Utility/FileSpec.h" // for FileSpec #include "lldb/Utility/Iterable.h" #include "lldb/Utility/Status.h" // for Status @@ -74,6 +75,14 @@ namespace lldb_private { +class ModuleListProperties : public Properties { +public: + ModuleListProperties(); + + FileSpec GetClangModulesCachePath() const; + bool SetClangModulesCachePath(llvm::StringRef path); +}; + //---------------------------------------------------------------------- /// @class ModuleList ModuleList.h "lldb/Core/ModuleList.h" /// @brief A collection class for Module objects. @@ -534,6 +543,8 @@ Stream *feedback_stream = nullptr, bool continue_on_error = true); + static ModuleListProperties &GetGlobalModuleListProperties(); + static bool ModuleIsInCache(const Module *module_ptr); static Status GetSharedModule(const ModuleSpec &module_spec, @@ -551,7 +562,7 @@ static size_t RemoveOrphanSharedModules(bool mandatory); static bool RemoveSharedModuleIfOrphaned(const Module *module_ptr); - + void ForEach(std::function const &callback) const; Index: lldb/trunk/include/lldb/Target/Target.h =================================================================== --- lldb/trunk/include/lldb/Target/Target.h +++ lldb/trunk/include/lldb/Target/Target.h @@ -126,8 +126,6 @@ FileSpecList &GetDebugFileSearchPaths(); - FileSpec &GetClangModulesCachePath(); - FileSpecList &GetClangModuleSearchPaths(); bool GetEnableAutoImportClangModules() const; Index: lldb/trunk/packages/Python/lldbsuite/test/lang/objc/modules-cache/Makefile =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/lang/objc/modules-cache/Makefile +++ lldb/trunk/packages/Python/lldbsuite/test/lang/objc/modules-cache/Makefile @@ -0,0 +1,4 @@ +LEVEL = ../../../make +OBJC_SOURCES := main.m +include $(LEVEL)/Makefile.rules +CFLAGS += $(MANDATORY_MODULE_BUILD_CFLAGS) -I$(SRCDIR) Index: lldb/trunk/packages/Python/lldbsuite/test/lang/objc/modules-cache/TestClangModulesCache.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/lang/objc/modules-cache/TestClangModulesCache.py +++ lldb/trunk/packages/Python/lldbsuite/test/lang/objc/modules-cache/TestClangModulesCache.py @@ -0,0 +1,40 @@ +"""Test that the clang modules cache directory can be controlled.""" + +from __future__ import print_function + + +import unittest2 +import os +import time +import platform +import shutil + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class ObjCModulesTestCase(TestBase): + NO_DEBUG_INFO_TESTCASE = True + mydir = TestBase.compute_mydir(__file__) + + def setUp(self): + TestBase.setUp(self) + + def test_expr(self): + self.build() + self.main_source_file = lldb.SBFileSpec("main.m") + self.runCmd("settings set target.auto-import-clang-modules true") + mod_cache = self.getBuildArtifact("my-clang-modules-cache") + if os.path.isdir(mod_cache): + shutil.rmtree(mod_cache) + self.assertFalse(os.path.isdir(mod_cache), + "module cache should not exist") + self.runCmd('settings set clang.modules-cache-path "%s"' % mod_cache) + self.runCmd('settings set target.clang-module-search-paths "%s"' + % self.getSourceDir()) + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( + self, "Set breakpoint here", self.main_source_file) + self.runCmd("expr @import Darwin") + self.assertTrue(os.path.isdir(mod_cache), "module cache exists") Index: lldb/trunk/packages/Python/lldbsuite/test/lang/objc/modules-cache/f.h =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/lang/objc/modules-cache/f.h +++ lldb/trunk/packages/Python/lldbsuite/test/lang/objc/modules-cache/f.h @@ -0,0 +1 @@ +void f() {} Index: lldb/trunk/packages/Python/lldbsuite/test/lang/objc/modules-cache/main.m =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/lang/objc/modules-cache/main.m +++ lldb/trunk/packages/Python/lldbsuite/test/lang/objc/modules-cache/main.m @@ -0,0 +1,5 @@ +@import Foo; +int main() { + f(); // Set breakpoint here. + return 0; +} Index: lldb/trunk/packages/Python/lldbsuite/test/lang/objc/modules-cache/module.modulemap =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/lang/objc/modules-cache/module.modulemap +++ lldb/trunk/packages/Python/lldbsuite/test/lang/objc/modules-cache/module.modulemap @@ -0,0 +1,3 @@ +module Foo { + header "f.h" +} Index: lldb/trunk/packages/Python/lldbsuite/test/lldbtest.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/lldbtest.py +++ lldb/trunk/packages/Python/lldbsuite/test/lldbtest.py @@ -1921,8 +1921,8 @@ if self.child: assert(self.getDebugInfo() == 'default') mod_cache = os.path.join(self.getBuildDir(), "module-cache") - self.runCmd("settings set target.clang-modules-cache-path " - + mod_cache) + self.runCmd('settings set clang.modules-cache-path "%s"' + % mod_cache) if "LLDB_MAX_LAUNCH_COUNT" in os.environ: Index: lldb/trunk/source/Core/Debugger.cpp =================================================================== --- lldb/trunk/source/Core/Debugger.cpp +++ lldb/trunk/source/Core/Debugger.cpp @@ -14,6 +14,7 @@ #include "lldb/Core/FormatEntity.h" #include "lldb/Core/Listener.h" // for Listener #include "lldb/Core/Mangled.h" // for Mangled +#include "lldb/Core/ModuleList.h" // for Mangled #include "lldb/Core/PluginManager.h" #include "lldb/Core/State.h" #include "lldb/Core/StreamAsynchronousIO.h" @@ -774,6 +775,9 @@ m_collection_sp->AppendProperty( ConstString("platform"), ConstString("Platform settings."), true, Platform::GetGlobalPlatformProperties()->GetValueProperties()); + m_collection_sp->AppendProperty( + ConstString("clang"), ConstString("Settings specific to Clang."), true, + ModuleList::GetGlobalModuleListProperties().GetValueProperties()); if (m_command_interpreter_ap) { m_collection_sp->AppendProperty( ConstString("interpreter"), Index: lldb/trunk/source/Core/ModuleList.cpp =================================================================== --- lldb/trunk/source/Core/ModuleList.cpp +++ lldb/trunk/source/Core/ModuleList.cpp @@ -13,6 +13,9 @@ #include "lldb/Core/ModuleSpec.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/Symbols.h" +#include "lldb/Interpreter/OptionValueProperties.h" +#include "lldb/Interpreter/OptionValueFileSpec.h" +#include "lldb/Interpreter/Property.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolContext.h" // for SymbolContextList, SymbolCon... #include "lldb/Symbol/VariableList.h" @@ -31,6 +34,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/Threading.h" #include "llvm/Support/raw_ostream.h" // for fs +#include "clang/Driver/Driver.h" #include // for operator!=, time_point #include // for shared_ptr @@ -60,6 +64,40 @@ using namespace lldb; using namespace lldb_private; +namespace { + +PropertyDefinition g_properties[] = { + {"modules-cache-path", OptionValue::eTypeFileSpec, true, 0, nullptr, + nullptr, + "The path to the clang modules cache directory (-fmodules-cache-path)."}, + {nullptr, OptionValue::eTypeInvalid, false, 0, nullptr, nullptr, nullptr}}; + +enum { ePropertyClangModulesCachePath }; + +} // namespace + +ModuleListProperties::ModuleListProperties() { + m_collection_sp.reset(new OptionValueProperties(ConstString("clang"))); + m_collection_sp->Initialize(g_properties); + + llvm::SmallString<128> path; + clang::driver::Driver::getDefaultModuleCachePath(path); + SetClangModulesCachePath(path); +} + +FileSpec ModuleListProperties::GetClangModulesCachePath() const { + return m_collection_sp + ->GetPropertyAtIndexAsOptionValueFileSpec(nullptr, false, + ePropertyClangModulesCachePath) + ->GetCurrentValue(); +} + +bool ModuleListProperties::SetClangModulesCachePath(llvm::StringRef path) { + return m_collection_sp->SetPropertyAtIndexAsString( + nullptr, ePropertyClangModulesCachePath, path); +} + + ModuleList::ModuleList() : m_modules(), m_modules_mutex(), m_notifier(nullptr) {} @@ -673,17 +711,32 @@ return LLDB_INVALID_INDEX32; } -static ModuleList &GetSharedModuleList() { - static ModuleList *g_shared_module_list = nullptr; +namespace { +struct SharedModuleListInfo { + ModuleList module_list; + ModuleListProperties module_list_properties; +}; +} +static SharedModuleListInfo &GetSharedModuleListInfo() +{ + static SharedModuleListInfo *g_shared_module_list_info = nullptr; static llvm::once_flag g_once_flag; llvm::call_once(g_once_flag, []() { // NOTE: Intentionally leak the module list so a program doesn't have to // cleanup all modules and object files as it exits. This just wastes time // doing a bunch of cleanup that isn't required. - if (g_shared_module_list == nullptr) - g_shared_module_list = new ModuleList(); // <--- Intentional leak!!! + if (g_shared_module_list_info == nullptr) + g_shared_module_list_info = new SharedModuleListInfo(); }); - return *g_shared_module_list; + return *g_shared_module_list_info; +} + +static ModuleList &GetSharedModuleList() { + return GetSharedModuleListInfo().module_list; +} + +ModuleListProperties &ModuleList::GetGlobalModuleListProperties() { + return GetSharedModuleListInfo().module_list_properties; } bool ModuleList::ModuleIsInCache(const Module *module_ptr) { Index: lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp =================================================================== --- lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp +++ lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp @@ -13,7 +13,6 @@ // Other libraries and framework includes #include "clang/Basic/TargetInfo.h" -#include "clang/Driver/Driver.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Lex/Preprocessor.h" @@ -28,6 +27,7 @@ // Project includes #include "ClangModulesDeclVendor.h" +#include "lldb/Core/ModuleList.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Symbol/CompileUnit.h" @@ -591,12 +591,11 @@ // Add additional search paths with { "-I", path } or { "-F", path } here. { - llvm::SmallString<128> Path; - target.GetClangModulesCachePath().GetPath(Path); - if (Path.empty()) - clang::driver::Driver::getDefaultModuleCachePath(Path); + llvm::SmallString<128> path; + auto props = ModuleList::GetGlobalModuleListProperties(); + props.GetClangModulesCachePath().GetPath(path); std::string module_cache_argument("-fmodules-cache-path="); - module_cache_argument.append(Path.str()); + module_cache_argument.append(path.str()); compiler_invocation_arguments.push_back(module_cache_argument); } Index: lldb/trunk/source/Target/Target.cpp =================================================================== --- lldb/trunk/source/Target/Target.cpp +++ lldb/trunk/source/Target/Target.cpp @@ -3509,9 +3509,6 @@ OptionValue::eTypeString, nullptr, nullptr, "A list of trap handler function names, e.g. a common Unix user process " "one is _sigtramp."}, - {"clang-modules-cache-path", - OptionValue::eTypeFileSpec, false, 0, nullptr, nullptr, - "The path to the clang modules cache directory (-fmodules-cache-path)."}, {"display-runtime-support-values", OptionValue::eTypeBoolean, false, false, nullptr, nullptr, "If true, LLDB will show variables that are meant to " "support the operation of a language's runtime " @@ -3561,7 +3558,6 @@ ePropertyMemoryModuleLoadLevel, ePropertyDisplayExpressionsInCrashlogs, ePropertyTrapHandlerNames, - ePropertyClangModulesCachePath, ePropertyDisplayRuntimeSupportValues, ePropertyNonStopModeEnabled, ePropertyExperimental @@ -3941,15 +3937,6 @@ return option_value->GetCurrentValue(); } -FileSpec &TargetProperties::GetClangModulesCachePath() { - const uint32_t idx = ePropertyClangModulesCachePath; - OptionValueFileSpec *option_value = - m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpec(nullptr, false, - idx); - assert(option_value); - return option_value->GetCurrentValue(); -} - FileSpecList &TargetProperties::GetClangModuleSearchPaths() { const uint32_t idx = ePropertyClangModuleSearchPaths; OptionValueFileSpecList *option_value =