Skip to content

Avoid importing dynamic libraries and frameworks are already in the t… #4077

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lldb/include/lldb/Target/Target.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ class TargetProperties : public Properties {

bool GetSwiftReadMetadataFromDSYM() const;

bool GetSwiftAutoImportFrameworks() const;

bool GetEnableAutoImportClangModules() const;

bool GetUseAllCompilerFlags() const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1278,8 +1278,7 @@ static llvm::Expected<ParsedExpression> ParseAndImport(
Status error;
SourceModule module_info;
module_info.path.emplace_back("Swift");
swift::ModuleDecl *module =
swift_ast_context.GetModule(module_info, error);
swift::ModuleDecl *module = swift_ast_context.GetModule(module_info, error);

if (error.Fail() || !module) {
LLDB_LOG(log, "couldn't load Swift Standard Library\n");
Expand Down
3 changes: 1 addition & 2 deletions lldb/source/Plugins/ExpressionParser/Swift/SwiftREPL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -580,8 +580,7 @@ void SwiftREPL::CompleteCode(const std::string &current_code,
completion_module_info.path.push_back(ConstString("repl"));
swift::ModuleDecl *repl_module = nullptr;
if (m_completion_module_initialized)
repl_module =
swift_ast->GetModule(completion_module_info, error);
repl_module = swift_ast->GetModule(completion_module_info, error);
if (repl_module == nullptr) {
swift::ImplicitImportInfo importInfo;
importInfo.StdlibKind = swift::ImplicitStdlibKind::Stdlib;
Expand Down
90 changes: 63 additions & 27 deletions lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "swift/AST/SubstitutionMap.h"
#include "swift/AST/Type.h"
#include "swift/AST/Types.h"
#include "swift/AST/ASTWalker.h"
#include "swift/ASTSectionImporter/ASTSectionImporter.h"
#include "swift/Basic/DiagnosticOptions.h"
#include "swift/Basic/Dwarf.h"
Expand Down Expand Up @@ -3378,7 +3379,10 @@ void SwiftASTContext::CacheModule(swift::ModuleDecl *module) {
}

swift::ModuleDecl *SwiftASTContext::GetModule(const SourceModule &module,
Status &error) {
Status &error, bool *cached) {
if (cached)
*cached = false;

VALID_OR_RETURN(nullptr);
if (!module.path.size())
return nullptr;
Expand All @@ -3392,8 +3396,11 @@ swift::ModuleDecl *SwiftASTContext::GetModule(const SourceModule &module,
return nullptr;
}

if (swift::ModuleDecl *module_decl = GetCachedModule(module))
if (swift::ModuleDecl *module_decl = GetCachedModule(module)) {
if (cached)
*cached = true;
return module_decl;
}

LLDB_SCOPED_TIMER();
swift::ASTContext *ast = GetASTContext();
Expand Down Expand Up @@ -3527,27 +3534,33 @@ swift::ModuleDecl *SwiftASTContext::GetModule(const FileSpec &module_spec,
return NULL;
}

swift::ModuleDecl *
SwiftASTContext::FindAndLoadModule(const SourceModule &module, Process &process,
Status &error) {
template<typename ModuleT> swift::ModuleDecl *
SwiftASTContext::FindAndLoadModule(const ModuleT &module, Process &process,
bool import_dylib, Status &error) {
VALID_OR_RETURN(nullptr);

swift::ModuleDecl *swift_module = GetModule(module, error);
bool cached = false;
swift::ModuleDecl *swift_module = GetModule(module, error, &cached);

if (!swift_module)
return nullptr;
LoadModule(swift_module, process, error);
return swift_module;
}

swift::ModuleDecl *
SwiftASTContext::FindAndLoadModule(const FileSpec &module_spec,
Process &process, Status &error) {
VALID_OR_RETURN(nullptr);
// If import_dylib is true, this is an explicit "import Module"
// declaration in a user expression, and we should load the dylib
// even if we already cached an implicit import (which may not have
// loaded the dylib). If target.swift-auto-import-frameworks is
// set, all implicitly imported Swift modules' associated frameworks
// will be imported too.
TargetSP target_sp(GetTargetWP().lock());
if (target_sp)
import_dylib |= target_sp->GetSwiftAutoImportFrameworks();

if (cached && !import_dylib)
return swift_module;

if (import_dylib)
LoadModule(swift_module, process, error);

swift::ModuleDecl *swift_module = GetModule(module_spec, error);
if (!swift_module)
return nullptr;
LoadModule(swift_module, process, error);
return swift_module;
}

Expand Down Expand Up @@ -3615,6 +3628,13 @@ void SwiftASTContext::LoadModule(swift::ModuleDecl *swift_module,
// name are the same, and that we are contained in
// FileName.framework with no other intervening frameworks. We
// can get more restrictive if this gives false positives.
//
// If the framework exists on disk but it's a static framework
// (i.e., the binary inside is a static archive instead of a
// dylib) this cannot be detected. The dlopen call will fail,
// and dlerror does not contain enough information to
// unambiguously identify this case. So it will look as if the
// framework hasn't been found.
ConstString library_cstr(library_name);

std::string framework_name(library_name);
Expand Down Expand Up @@ -8149,6 +8169,7 @@ static void GetNameFromModule(swift::ModuleDecl *module, std::string &result) {
static swift::ModuleDecl *LoadOneModule(const SourceModule &module,
SwiftASTContext &swift_ast_context,
lldb::ProcessSP process_sp,
bool import_dylibs,
Status &error) {
LLDB_SCOPED_TIMER();
if (!module.path.size())
Expand All @@ -8167,8 +8188,8 @@ static swift::ModuleDecl *LoadOneModule(const SourceModule &module,
toplevel.GetStringRef() == imported_header_module->getName().str())
swift_module = imported_header_module;
else if (process_sp)
swift_module =
swift_ast_context.FindAndLoadModule(module, *process_sp.get(), error);
swift_module = swift_ast_context.FindAndLoadModule(
module, *process_sp.get(), import_dylibs, error);
else
swift_module = swift_ast_context.GetModule(module, error);

Expand Down Expand Up @@ -8243,8 +8264,8 @@ bool SwiftASTContext::GetImplicitImports(
// Otherwise, try reloading the ModuleDecl using the module name.
SourceModule module_info;
module_info.path.emplace_back(module_pair.first());
auto *module =
LoadOneModule(module_info, swift_ast_context, process_sp, error);
auto *module = LoadOneModule(module_info, swift_ast_context, process_sp,
/*import_dylibs=*/false, error);
if (!module)
return false;

Expand Down Expand Up @@ -8273,10 +8294,24 @@ bool SwiftASTContext::CacheUserImports(SwiftASTContext &swift_ast_context,

size_t completion = 0;

/// Find all explicit imports in the expression.
struct UserImportFinder : public swift::ASTWalker {
llvm::SmallDenseSet<swift::ModuleDecl*, 1> imports;

bool walkToDeclPre(swift::Decl *D) override {
if (auto *ID = llvm::dyn_cast<swift::ImportDecl>(D))
if (auto *M = ID->getModule())
imports.insert(M);
return true;
}
};
UserImportFinder import_finder;
source_file.walk(import_finder);

for (const auto &attributed_import : src_file_imports) {
progress.Increment(++completion);
swift::ModuleDecl *module = attributed_import.module.importedModule;
if (module) {
if (module && import_finder.imports.count(module)) {
std::string module_name;
GetNameFromModule(module, module_name);
if (!module_name.empty()) {
Expand All @@ -8286,7 +8321,8 @@ bool SwiftASTContext::CacheUserImports(SwiftASTContext &swift_ast_context,
LOG_PRINTF(GetLog(LLDBLog::Types | LLDBLog::Expressions),
"Performing auto import on found module: %s.\n",
module_name.c_str());
if (!LoadOneModule(module_info, swift_ast_context, process_sp, error))
if (!LoadOneModule(module_info, swift_ast_context, process_sp,
/*import_dylibs=*/true, error))
return false;

// How do we tell we are in REPL or playground mode?
Expand Down Expand Up @@ -8340,8 +8376,8 @@ bool SwiftASTContext::GetCompileUnitImportsImpl(
// Import the Swift standard library and its dependencies.
SourceModule swift_module;
swift_module.path.emplace_back("Swift");
auto *stdlib =
LoadOneModule(swift_module, *this, process_sp, error);
auto *stdlib = LoadOneModule(swift_module, *this, process_sp,
/*import_dylibs=*/true, error);
if (!stdlib)
return false;

Expand Down Expand Up @@ -8370,8 +8406,8 @@ bool SwiftASTContext::GetCompileUnitImportsImpl(
.Default(false))
continue;

auto *loaded_module =
LoadOneModule(module, *this, process_sp, error);
auto *loaded_module = LoadOneModule(module, *this, process_sp,
/*import_dylibs=*/false, error);
if (!loaded_module)
return false;

Expand Down
18 changes: 8 additions & 10 deletions lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,21 +285,19 @@ class SwiftASTContext : public TypeSystemSwift {
// for all items in a swift::ASTContext have been setup to
// allow for imports to happen correctly. Use with caution,
// or use the GetModule() call that takes a FileSpec.
swift::ModuleDecl *GetModule(const SourceModule &module, Status &error);
swift::ModuleDecl *GetModule(const SourceModule &module, Status &error,
bool *cached = nullptr);

swift::ModuleDecl *GetModule(const FileSpec &module_spec, Status &error);

void CacheModule(swift::ModuleDecl *module);

// Call this after the search paths are set up, it will find the module given
// by module, load the module into the AST context, and also load any
// "LinkLibraries" that the module requires.

swift::ModuleDecl *FindAndLoadModule(const SourceModule &module,
Process &process, Status &error);

swift::ModuleDecl *FindAndLoadModule(const FileSpec &module_spec,
Process &process, Status &error);
/// Call this after the search paths are set up, it will find the module given
/// by module, load the module into the AST context, and (if import_dylib is
/// set) also load any "LinkLibraries" that the module requires.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worthwhile to note here that the auto-import setting overrides the value of import_dylib.

template <typename ModuleT>
swift::ModuleDecl *FindAndLoadModule(const ModuleT &module, Process &process,
bool import_dylib, Status &error);

void LoadModule(swift::ModuleDecl *swift_module, Process &process,
Status &error);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1321,8 +1321,9 @@ TypeSystemSwiftTypeRefForExpressions::TypeSystemSwiftTypeRefForExpressions(
void TypeSystemSwiftTypeRefForExpressions::PerformCompileUnitImports(
SymbolContext &sc) {
Status error;
// FIXME: this is uninitialized!
lldb::ProcessSP process_sp;
if (auto target_sp = sc.target_sp)
process_sp = target_sp->GetProcessSP();
if (m_swift_ast_context_initialized)
GetSwiftASTContext()->PerformCompileUnitImports(sc, process_sp, error);
else
Expand Down Expand Up @@ -1383,8 +1384,9 @@ TypeSystemSwiftTypeRefForExpressions::GetSwiftASTContext() const {

if (m_initial_symbol_context) {
Status error;
// FIXME: not initialized!
lldb::ProcessSP process_sp;
if (TargetSP target_sp = GetTargetWP().lock())
process_sp = target_sp->GetProcessSP();
m_swift_ast_context->PerformCompileUnitImports(*m_initial_symbol_context,
process_sp, error);
m_initial_symbol_context.reset();
Expand Down
8 changes: 8 additions & 0 deletions lldb/source/Target/Target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4175,6 +4175,7 @@ bool TargetProperties::GetSwiftCreateModuleContextsInParallel() const {
return true;
}


bool TargetProperties::GetSwiftReadMetadataFromFileCache() const {
const Property *exp_property = m_collection_sp->GetPropertyAtIndex(
nullptr, false, ePropertyExperimental);
Expand Down Expand Up @@ -4210,6 +4211,13 @@ bool TargetProperties::GetSwiftReadMetadataFromDSYM() const {

return true;
}

bool TargetProperties::GetSwiftAutoImportFrameworks() const {
const uint32_t idx = ePropertySwiftAutoImportFrameworks;
return m_collection_sp->GetPropertyAtIndexAsBoolean(
nullptr, idx, g_target_properties[idx].default_uint_value != 0);
}

ArchSpec TargetProperties::GetDefaultArchitecture() const {
OptionValueArch *value = m_collection_sp->GetPropertyAtIndexAsOptionValueArch(
nullptr, ePropertyDefaultArch);
Expand Down
3 changes: 3 additions & 0 deletions lldb/source/Target/TargetProperties.td
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,9 @@ let Definition = "target" in {
def SwiftExtraClangFlags: Property<"swift-extra-clang-flags", "String">,
DefaultStringValue<"">,
Desc<"Additional -Xcc flags to be passed to the Swift ClangImporter.">;
def SwiftAutoImportFrameworks : Property<"swift-auto-import-frameworks", "Boolean">,
DefaultFalse,
Desc<"Automatically import all frameworks and dynamic libraries that are autolinked by Swift modules in the target.">;
def UseAllCompilerFlags: Property<"use-all-compiler-flags", "Boolean">,
DefaultTrue,
Desc<"Try to use compiler flags for all modules when setting up the Swift expression parser, not just the main executable.">;
Expand Down
5 changes: 5 additions & 0 deletions lldb/test/API/lang/swift/lazy_framework/Lazy.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
public typealias MyNumber = Int
public class C {
public init() { n = MyNumber(23) }
let n : MyNumber
}
15 changes: 15 additions & 0 deletions lldb/test/API/lang/swift/lazy_framework/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
SWIFT_SOURCES := main.swift

SWIFTFLAGS_EXTRAS = -F $(BUILDDIR)

all: Lazy.framework $(EXE)

include Makefile.rules

Lazy.framework: $(SRCDIR)/Lazy.swift
$(MAKE) -f $(MAKEFILE_RULES) \
DYLIB_NAME=Lazy \
DYLIB_SWIFT_SOURCES=Lazy.swift \
DYLIB_MODULENAME=Lazy \
FRAMEWORK=Lazy
rm -f $(BUILDDIR)/Lazy.swiftmodule $(BUILDDIR)/Lazy.swiftinterface
35 changes: 35 additions & 0 deletions lldb/test/API/lang/swift/lazy_framework/TestSwiftLazyFramework.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import lldb
from lldbsuite.test.decorators import *
import lldbsuite.test.lldbtest as lldbtest
import lldbsuite.test.lldbutil as lldbutil
import os
import unittest2


class TestSwiftLazyFramework(lldbtest.TestBase):

NO_DEBUG_INFO_TESTCASE = True
mydir = lldbtest.TestBase.compute_mydir(__file__)

@swiftTest
@skipIf(oslist=no_match(["macosx"]))
def test_system_framework(self):
"""Test that a framework that is registered as autolinked in a Swift
module used in the target, but not linked against the target is
automatically loaded by LLDB."""
self.build()
self.expect("settings set target.swift-auto-import-frameworks true")
target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
self, 'break here', lldb.SBFileSpec('main.swift'))

# Verify that lazy is not linked in.
self.runCmd("image list")
output = self.res.GetOutput()
self.assertIn("dyld", output)
self.assertNotIn("Lazy.framework/Versions/A/Lazy", output)
# FIXME: we should automatically retry the expression on dylib import.
self.expect("expression -- 1", error=True)
self.expect("expression -- C()", substrs=['23'])

# Verify that lazy has been dynamically loaded.
self.expect("image list", substrs=["Lazy.framework/Versions/A/Lazy"])
4 changes: 4 additions & 0 deletions lldb/test/API/lang/swift/lazy_framework/main.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import Lazy
let n = MyNumber(42)
print("break here")
print(n)
1 change: 1 addition & 0 deletions lldb/test/API/lang/swift/static_framework/Dylib.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
public struct D { public init() {} }
36 changes: 36 additions & 0 deletions lldb/test/API/lang/swift/static_framework/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
SWIFT_SOURCES := main.swift

SWIFTFLAGS_EXTRAS = -I$(BUILDDIR) -F$(BUILDDIR)

FRAMEWORKS=$(patsubst %,a%.framework,$(shell seq -s " " 0 $(N)))

all: $(FRAMEWORKS) dylib $(EXE)

include Makefile.rules

lib%.a: %.swift
$(MAKE) -f $(MAKEFILE_RULES) \
DYLIB_NAME=static \
SWIFT_SOURCES=$(patsubst lib%.a,%.swift,$@) \
MODULENAME=$(patsubst lib%.a,%,$@) \
SWIFTFLAGS_EXTRAS="$(patsubst %,-F%/DOES_NOT_EXIST,$(FRAMEWORKS))" \
$(patsubst lib%.a,%.o,$@) \
$(patsubst lib%.a,%.swiftmodule,$@)
ar -r $@ $(BUILDDIR)/$(patsubst lib%.a,%.o,$@)

%.framework: lib%.a
mkdir -p $(BUILDDIR)/$@/Headers
mkdir -p $(BUILDDIR)/$@/Modules
mkdir -p $(BUILDDIR)/$@/Resources
mv $< $(BUILDDIR)/$@/$(patsubst lib%.a,%,$<)
mkdir -p $(BUILDDIR)/$@/Modules/$(patsubst lib%.a,%.swiftmodule,$<)
mv $(BUILDDIR)/$(patsubst lib%.a,%.swiftmodule,$<) $(BUILDDIR)/$@/Modules/$(patsubst lib%.a,%.swiftmodule,$<)/$(ARCH)-apple-macos.swiftmodule
mv $(BUILDDIR)/$(patsubst lib%.a,%.swiftinterface,$<) $(BUILDDIR)/$@/Modules/

dylib: Dylib.swift
$(MAKE) -f $(MAKEFILE_RULES) \
DYLIB_NAME=Dylib \
DYLIB_SWIFT_SOURCES=Dylib.swift \
DYLIB_MODULENAME=Dylib \
FRAMEWORK=Dylib
rm -f $(BUILDDIR)/Dylib.swiftmodule $(BUILDDIR)/Dylib.swiftinterface
Loading