[lldb/cmake] Plugin layering enforcement mechanism (#144543)
Some inter-plugin dependencies are okay, others are not. Yet others not, but we're sort of stuck with them. The idea is to be able to prevent backsliding while making sure that acceptable dependencies are.. accepted. For context, see https://github.com/llvm/llvm-project/pull/139170 and the attached changes to the documentation.
This commit is contained in:
@@ -37,6 +37,7 @@ endif()
|
||||
|
||||
include(LLDBConfig)
|
||||
include(AddLLDB)
|
||||
include(LLDBLayeringCheck)
|
||||
|
||||
set(LLDB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
@@ -127,6 +128,8 @@ add_subdirectory(source)
|
||||
add_subdirectory(tools)
|
||||
add_subdirectory(docs)
|
||||
|
||||
check_lldb_plugin_layering()
|
||||
|
||||
if (LLDB_ENABLE_PYTHON)
|
||||
if(LLDB_BUILD_FRAMEWORK)
|
||||
set(lldb_python_target_dir "${LLDB_FRAMEWORK_ABSOLUTE_BUILD_DIR}/LLDB.framework/Resources/Python/lldb")
|
||||
|
||||
68
lldb/cmake/modules/LLDBLayeringCheck.cmake
Normal file
68
lldb/cmake/modules/LLDBLayeringCheck.cmake
Normal file
@@ -0,0 +1,68 @@
|
||||
define_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND)
|
||||
define_property(TARGET PROPERTY LLDB_PLUGIN_KIND INHERITED)
|
||||
|
||||
define_property(DIRECTORY PROPERTY LLDB_ACCEPTABLE_PLUGIN_DEPENDENCIES)
|
||||
define_property(TARGET PROPERTY LLDB_ACCEPTABLE_PLUGIN_DEPENDENCIES INHERITED)
|
||||
|
||||
define_property(DIRECTORY PROPERTY LLDB_TOLERATED_PLUGIN_DEPENDENCIES)
|
||||
define_property(TARGET PROPERTY LLDB_TOLERATED_PLUGIN_DEPENDENCIES INHERITED)
|
||||
|
||||
option(LLDB_GENERATE_PLUGIN_DEP_GRAPH OFF)
|
||||
|
||||
function(check_lldb_plugin_layering)
|
||||
get_property(plugins GLOBAL PROPERTY LLDB_PLUGINS)
|
||||
foreach(plugin ${plugins})
|
||||
get_property(plugin_kind TARGET ${plugin} PROPERTY LLDB_PLUGIN_KIND)
|
||||
get_property(acceptable_deps TARGET ${plugin}
|
||||
PROPERTY LLDB_ACCEPTABLE_PLUGIN_DEPENDENCIES)
|
||||
get_property(tolerated_deps TARGET ${plugin}
|
||||
PROPERTY LLDB_TOLERATED_PLUGIN_DEPENDENCIES)
|
||||
|
||||
# A plugin is always permitted to depend on its own kind for the purposes
|
||||
# subclassing. Ideally the intra-kind dependencies should not form a loop,
|
||||
# but we're not checking that here.
|
||||
list(APPEND acceptable_deps ${plugin_kind})
|
||||
|
||||
list(APPEND all_plugin_kinds ${plugin_kind})
|
||||
|
||||
get_property(link_libs TARGET ${plugin} PROPERTY LINK_LIBRARIES)
|
||||
foreach(link_lib ${link_libs})
|
||||
if(link_lib IN_LIST plugins)
|
||||
get_property(lib_kind TARGET ${link_lib} PROPERTY LLDB_PLUGIN_KIND)
|
||||
if (lib_kind)
|
||||
if (lib_kind IN_LIST acceptable_deps)
|
||||
set(dep_kind green)
|
||||
elseif (lib_kind IN_LIST tolerated_deps)
|
||||
set(dep_kind yellow)
|
||||
else()
|
||||
set(dep_kind red)
|
||||
message(SEND_ERROR "Plugin ${plugin} cannot depend on ${lib_kind} "
|
||||
"plugin ${link_lib}")
|
||||
endif()
|
||||
list(APPEND dep_${dep_kind}_${plugin_kind}_${lib_kind} ${plugin})
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
if (LLDB_GENERATE_PLUGIN_DEP_GRAPH)
|
||||
set(dep_graph "digraph Plugins {\n")
|
||||
list(REMOVE_DUPLICATES all_plugin_kinds)
|
||||
foreach (from ${all_plugin_kinds})
|
||||
foreach (to ${all_plugin_kinds})
|
||||
foreach (dep_kind green yellow red)
|
||||
if (dep_${dep_kind}_${from}_${to})
|
||||
list(REMOVE_DUPLICATES dep_${dep_kind}_${from}_${to})
|
||||
string(REGEX REPLACE "lldbPlugin|${from}" "" short_deps
|
||||
"${dep_${dep_kind}_${from}_${to}}")
|
||||
string(JOIN "\n" plugins ${short_deps})
|
||||
string(APPEND dep_graph
|
||||
" ${from}->${to}[color=\"${dep_kind}\" label=\"${plugins}\"];\n")
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
endforeach()
|
||||
string(APPEND dep_graph "}\n")
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/lldb-plugin-deps.dot" "${dep_graph}")
|
||||
endif()
|
||||
endfunction()
|
||||
@@ -56,6 +56,56 @@ subset of LLDB tests (the API tests) use a different system. Refer to the
|
||||
`lldb/test <https://github.com/llvm/llvm-project/tree/main/lldb/test>`_ folder
|
||||
for examples.
|
||||
|
||||
|
||||
LLDB plugins and their dependencies
|
||||
-----------------------------------
|
||||
|
||||
LLDB has a concept of *plugins*, which are used to provide abstraction
|
||||
boundaries over functionality that is specific to a certain architecture,
|
||||
operating system, programming language, etc. A plugin implements an abstract
|
||||
base class (rarely, a set of related base classes), which is a part of LLDB
|
||||
core. This setup allows the LLDB core to remain generic while making it possible
|
||||
to support for new architectures, languages, and so on. For this to work, all
|
||||
code needs to obey certain rules.
|
||||
|
||||
The principal rule is that LLDB core (defined as: everything under lldb/source
|
||||
*minus* lldb/source/Plugins) must not depend on any specific plugin. The only
|
||||
way it can interact with them is through the abstract interface. Explicit
|
||||
dependencies such as casting the base class to the plugin type are not permitted
|
||||
and neither are more subtle dependencies like checking the name plugin or or
|
||||
other situations where some code in LLDB core is tightly coupled to the
|
||||
implementation details of a specific plugin.
|
||||
|
||||
The rule for interaction between different plugins is more nuanced. We recognize
|
||||
that some cross-plugin dependencies are unavoidable or even desirable. For
|
||||
example, a plugin may want to extend a plugin of the same kind to
|
||||
add/override/refine some functionality (e.g., Android is a "kind of" Linux, but
|
||||
it handles some things differently). Alternatively, a plugin of one kind may
|
||||
want to build on the functionality offered by a specific plugin of another kind
|
||||
(ELFCore Process plugin uses ELF ObjectFile plugin to create a process out of an
|
||||
ELF core file).
|
||||
|
||||
In cases such as these, direct dependencies are acceptable. However, to keep the
|
||||
dependency graph manageable, we still have some rules to govern these
|
||||
relationships:
|
||||
|
||||
* All dependencies between plugins of the same kind must flow in the same
|
||||
direction (if plugin `A1` depends on plugin `B1`, then `B2` must not depend on
|
||||
`A2`)
|
||||
* Dependency graph of plugin kinds must not contain loops (dependencies like
|
||||
`A1->B1`, `B2->C2` and `C3->A3` are forbidden because they induce a cycle in
|
||||
the plugin kind graph even though the plugins themselves are acyclical)
|
||||
|
||||
|
||||
The first of these rules is checked via CMake scripts (using the
|
||||
`LLDB_ACCEPTABLE_PLUGIN_DEPENDENCIES` property). Dependencies in this category
|
||||
are expected and permitted (subject to other constraints such as that dependency
|
||||
making sense for the particular pair of plugins). Unfortunately, due to historic
|
||||
reasons, not all plugin dependencies follow this rule, which is why we have
|
||||
another category called `LLDB_TOLERATED_PLUGIN_DEPENDENCIES`. New dependencies
|
||||
are forbidden (even though they are accepted by CMake) and existing ones should
|
||||
be removed whereever possible.
|
||||
|
||||
.. _Error handling:
|
||||
|
||||
Error handling and use of assertions in LLDB
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND ABI)
|
||||
set_property(DIRECTORY PROPERTY LLDB_TOLERATED_PLUGIN_DEPENDENCIES
|
||||
ProcessUtility
|
||||
TypeSystem
|
||||
)
|
||||
|
||||
foreach(target AArch64 ARM ARC Hexagon LoongArch Mips MSP430 PowerPC RISCV SystemZ X86)
|
||||
if (${target} IN_LIST LLVM_TARGETS_TO_BUILD)
|
||||
add_subdirectory(${target})
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND Architecture)
|
||||
|
||||
add_subdirectory(Arm)
|
||||
add_subdirectory(Mips)
|
||||
add_subdirectory(PPC64)
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND Disassembler)
|
||||
|
||||
add_subdirectory(LLVMC)
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND DynamicLoader)
|
||||
set_property(DIRECTORY PROPERTY LLDB_ACCEPTABLE_PLUGIN_DEPENDENCIES ObjectFile)
|
||||
set_property(DIRECTORY PROPERTY LLDB_TOLERATED_PLUGIN_DEPENDENCIES
|
||||
Process # part of a loop (Process<->DynamicLoader).
|
||||
TypeSystem
|
||||
)
|
||||
|
||||
add_subdirectory(Darwin-Kernel)
|
||||
add_subdirectory(FreeBSD-Kernel)
|
||||
add_subdirectory(MacOSX-DYLD)
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND ExpressionParser)
|
||||
|
||||
add_subdirectory(Clang)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND Instruction)
|
||||
|
||||
add_subdirectory(ARM)
|
||||
add_subdirectory(ARM64)
|
||||
add_subdirectory(LoongArch)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND InstrumentationRuntime)
|
||||
|
||||
add_subdirectory(ASan)
|
||||
add_subdirectory(ASanLibsanitizers)
|
||||
add_subdirectory(MainThreadChecker)
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND JITLoader)
|
||||
set_property(DIRECTORY PROPERTY LLDB_TOLERATED_PLUGIN_DEPENDENCIES ObjectFile)
|
||||
|
||||
add_subdirectory(GDB)
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND Language)
|
||||
set_property(DIRECTORY PROPERTY LLDB_TOLERATED_PLUGIN_DEPENDENCIES
|
||||
LanguageRuntime
|
||||
TypeSystem
|
||||
)
|
||||
|
||||
add_subdirectory(ClangCommon)
|
||||
add_subdirectory(CPlusPlus)
|
||||
add_subdirectory(ObjC)
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND LanguageRuntime)
|
||||
set_property(DIRECTORY PROPERTY LLDB_TOLERATED_PLUGIN_DEPENDENCIES TypeSystem)
|
||||
|
||||
add_subdirectory(CPlusPlus)
|
||||
add_subdirectory(ObjC)
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND MemoryHistory)
|
||||
|
||||
add_subdirectory(asan)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND ObjectContainer)
|
||||
|
||||
add_subdirectory(BSD-Archive)
|
||||
add_subdirectory(Universal-Mach-O)
|
||||
add_subdirectory(Mach-O-Fileset)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND ObjectFile)
|
||||
|
||||
add_subdirectory(Breakpad)
|
||||
add_subdirectory(COFF)
|
||||
add_subdirectory(ELF)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND OperatingSystem)
|
||||
|
||||
if (LLDB_ENABLE_PYTHON)
|
||||
add_subdirectory(Python)
|
||||
endif()
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND Platform)
|
||||
set_property(DIRECTORY PROPERTY LLDB_TOLERATED_PLUGIN_DEPENDENCIES
|
||||
DynamicLoader
|
||||
ObjectContainer
|
||||
Process
|
||||
)
|
||||
|
||||
add_subdirectory(AIX)
|
||||
add_subdirectory(Android)
|
||||
add_subdirectory(FreeBSD)
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND Process)
|
||||
set_property(DIRECTORY PROPERTY LLDB_ACCEPTABLE_PLUGIN_DEPENDENCIES ObjectFile)
|
||||
# This dependency is part of a loop (Process<->DynamicLoader).
|
||||
set_property(DIRECTORY PROPERTY LLDB_TOLERATED_PLUGIN_DEPENDENCIES DynamicLoader)
|
||||
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "Linux|Android")
|
||||
add_subdirectory(Linux)
|
||||
add_subdirectory(POSIX)
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
# TODO: Clean up this directory and its dependencies
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND ProcessUtility)
|
||||
|
||||
add_lldb_library(lldbPluginProcessUtility
|
||||
AuxVector.cpp
|
||||
FreeBSDSignals.cpp
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND REPL)
|
||||
set_property(DIRECTORY PROPERTY LLDB_ACCEPTABLE_PLUGIN_DEPENDENCIES TypeSystem)
|
||||
|
||||
add_subdirectory(Clang)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND RegisterTypeBuilder)
|
||||
|
||||
add_lldb_library(lldbPluginRegisterTypeBuilderClang PLUGIN
|
||||
RegisterTypeBuilderClang.cpp
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND ScriptInterpreter)
|
||||
|
||||
add_subdirectory(None)
|
||||
if (LLDB_ENABLE_PYTHON)
|
||||
add_subdirectory(Python)
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND StructuredData)
|
||||
|
||||
add_subdirectory(DarwinLog)
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND SymbolFile)
|
||||
set_property(DIRECTORY PROPERTY LLDB_ACCEPTABLE_PLUGIN_DEPENDENCIES ObjectFile)
|
||||
set_property(DIRECTORY PROPERTY LLDB_TOLERATED_PLUGIN_DEPENDENCIES
|
||||
Language
|
||||
TypeSystem # part of a loop (TypeSystem<->SymbolFile).
|
||||
)
|
||||
|
||||
add_subdirectory(Breakpad)
|
||||
add_subdirectory(CTF)
|
||||
add_subdirectory(DWARF)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND SymbolLocator)
|
||||
|
||||
# Order matters here: the first symbol locator prevents further searching.
|
||||
# For DWARF binaries that are both stripped and split, the Default plugin
|
||||
# will return the stripped binary when asked for the ObjectFile, which then
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND SymbolVendor)
|
||||
set_property(DIRECTORY PROPERTY LLDB_ACCEPTABLE_PLUGIN_DEPENDENCIES ObjectFile)
|
||||
|
||||
add_subdirectory(ELF)
|
||||
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND SystemRuntime)
|
||||
set_property(DIRECTORY PROPERTY LLDB_TOLERATED_PLUGIN_DEPENDENCIES TypeSystem)
|
||||
|
||||
add_subdirectory(MacOSX)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND Trace)
|
||||
|
||||
option(LLDB_BUILD_INTEL_PT "Enable Building of Intel(R) Processor Trace Tool" OFF)
|
||||
|
||||
add_subdirectory(common)
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND TraceExporter)
|
||||
|
||||
add_subdirectory(common)
|
||||
add_subdirectory(ctf)
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND TypeSystem)
|
||||
# This dependency is part of a loop (TypeSystem<->SymbolFile).
|
||||
set_property(DIRECTORY PROPERTY LLDB_TOLERATED_PLUGIN_DEPENDENCIES SymbolFile)
|
||||
|
||||
add_subdirectory(Clang)
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND UnwindAssembly)
|
||||
|
||||
add_subdirectory(InstEmulation)
|
||||
add_subdirectory(x86)
|
||||
|
||||
Reference in New Issue
Block a user