[Lldb-commits] [lldb] 4241ac5 - [lldb][gnustep] Add basic test and infrastructure for GNUstep ObjC runtime
Stefan Gränitz via lldb-commits
lldb-commits at lists.llvm.org
Wed May 17 01:39:30 PDT 2023
Author: Stefan Gränitz
Date: 2023-05-17T10:37:38+02:00
New Revision: 4241ac542d691289f08c3229cfc58641f5659ec7
URL: https://github.com/llvm/llvm-project/commit/4241ac542d691289f08c3229cfc58641f5659ec7
DIFF: https://github.com/llvm/llvm-project/commit/4241ac542d691289f08c3229cfc58641f5659ec7.diff
LOG: [lldb][gnustep] Add basic test and infrastructure for GNUstep ObjC runtime
This patch adds test infrastructure to utilize the GNUstep runtime in the LLDB test suite and adds coverage for features that already work on Linux. These seem accidental in parts, but it's a good early baseline. On Windows nothing works yet. Please find the repository for the GNUstep ObjC runtime here: https://github.com/gnustep/libobjc2
GNUstep support is disabled by default. CMake configuration involves two variables:
* `LLDB_TEST_OBJC_GNUSTEP=On` enables GNUstep support in the test suite. It requires the libobjc2 shared library and headers to be found.
* `LLDB_TEST_OBJC_GNUSTEP=Off` disables GNUstep support in the test suite and resets associated cache values if necessary (default).
* `LLDB_TEST_OBJC_GNUSTEP_DIR` allows to pass a custom installation root.
Differential Revision: https://reviews.llvm.org/D146058
Added:
lldb/cmake/modules/FindGNUstepObjC.cmake
lldb/test/Shell/Expr/objc-gnustep-print.m
Modified:
lldb/test/CMakeLists.txt
lldb/test/Shell/helper/build.py
lldb/test/Shell/helper/toolchain.py
lldb/test/Shell/lit.cfg.py
lldb/test/Shell/lit.site.cfg.py.in
Removed:
################################################################################
diff --git a/lldb/cmake/modules/FindGNUstepObjC.cmake b/lldb/cmake/modules/FindGNUstepObjC.cmake
new file mode 100644
index 0000000000000..e53a89e50a481
--- /dev/null
+++ b/lldb/cmake/modules/FindGNUstepObjC.cmake
@@ -0,0 +1,41 @@
+#.rst:
+# FindGNUstepObjC
+# ---------------
+#
+# Find the GNUstep libobjc2 shared library.
+
+set(gnustep_install_dir "")
+
+if (UNIX)
+ set(gnustep_lib lib/libobjc.so)
+ set(gnustep_header include/objc/runtime.h)
+ if (GNUstepObjC_DIR)
+ if (EXISTS "${GNUstepObjC_DIR}/${gnustep_lib}" AND
+ EXISTS "${GNUstepObjC_DIR}/${gnustep_header}")
+ set(gnustep_install_dir ${GNUstepObjC_DIR})
+ endif()
+ else()
+ set(gnustep_install_dir)
+ find_path(gnustep_install_dir NAMES lib/libobjc.so include/objc/runtime.h)
+ endif()
+ if (gnustep_install_dir)
+ set(GNUstepObjC_FOUND TRUE)
+ endif()
+elseif (WIN32)
+ set(gnustep_lib lib/objc.dll)
+ set(gnustep_header include/objc/runtime.h)
+ if (GNUstepObjC_DIR)
+ set(gnustep_install_dir ${GNUstepObjC_DIR})
+ else()
+ set(gnustep_install_dir "C:/Program Files (x86)/libobjc")
+ endif()
+ if (EXISTS "${gnustep_install_dir}/${gnustep_lib}" AND
+ EXISTS "${gnustep_install_dir}/${gnustep_header}")
+ set(GNUstepObjC_FOUND TRUE)
+ endif()
+endif()
+
+if (GNUstepObjC_FOUND)
+ set(GNUstepObjC_DIR ${gnustep_install_dir})
+ message(STATUS "Found GNUstep ObjC runtime: ${GNUstepObjC_DIR}/${gnustep_lib}")
+endif()
diff --git a/lldb/test/CMakeLists.txt b/lldb/test/CMakeLists.txt
index ca15b96586cad..38013e1df6188 100644
--- a/lldb/test/CMakeLists.txt
+++ b/lldb/test/CMakeLists.txt
@@ -50,6 +50,30 @@ set(LLDB_TEST_MODULE_CACHE_CLANG "${LLDB_TEST_BUILD_DIRECTORY}/module-cache-clan
file(MAKE_DIRECTORY ${LLDB_TEST_MODULE_CACHE_LLDB})
file(MAKE_DIRECTORY ${LLDB_TEST_MODULE_CACHE_CLANG})
+# Windows and Linux have no built-in ObjC runtime. Turn this on in order to run tests with GNUstep.
+option(LLDB_TEST_OBJC_GNUSTEP "Enable ObjC tests with GNUstep libobjc2 on non-Apple platforms" Off)
+set(LLDB_TEST_OBJC_GNUSTEP_DIR "" CACHE PATH "Custom path to the GNUstep shared library")
+
+if (LLDB_TEST_OBJC_GNUSTEP)
+ if (LLDB_TEST_OBJC_GNUSTEP_DIR)
+ set(GNUstepObjC_DIR ${LLDB_TEST_OBJC_GNUSTEP_DIR})
+ endif()
+ find_package(GNUstepObjC)
+ if (NOT GNUstepObjC_FOUND)
+ if (LLDB_TEST_OBJC_GNUSTEP_DIR)
+ message(FATAL_ERROR "Failed to find GNUstep libobjc2 in ${LLDB_TEST_OBJC_GNUSTEP_DIR}. "
+ "Please check LLDB_TEST_OBJC_GNUSTEP_DIR or turn off LLDB_TEST_OBJC_GNUSTEP.")
+ else()
+ message(FATAL_ERROR "Failed to find GNUstep libobjc2. "
+ "Please set LLDB_TEST_OBJC_GNUSTEP_DIR or turn off LLDB_TEST_OBJC_GNUSTEP.")
+ endif()
+ endif()
+ set(LLDB_TEST_OBJC_GNUSTEP_DIR ${GNUstepObjC_DIR})
+elseif (LLDB_TEST_OBJC_GNUSTEP_DIR)
+ message(STATUS "Reset LLDB_TEST_OBJC_GNUSTEP_DIR since LLDB_TEST_OBJC_GNUSTEP is off")
+ set(LLDB_TEST_OBJC_GNUSTEP_DIR "" CACHE PATH "Custom path to the GNUstep shared library" FORCE)
+endif()
+
# LLVM_BUILD_MODE is used in lit.site.cfg
if (CMAKE_CFG_INTDIR STREQUAL ".")
set(LLVM_BUILD_MODE ".")
diff --git a/lldb/test/Shell/Expr/objc-gnustep-print.m b/lldb/test/Shell/Expr/objc-gnustep-print.m
new file mode 100644
index 0000000000000..565a96f15a3f7
--- /dev/null
+++ b/lldb/test/Shell/Expr/objc-gnustep-print.m
@@ -0,0 +1,62 @@
+// REQUIRES: objc-gnustep
+// XFAIL: system-windows
+//
+// RUN: %build %s --compiler=clang --objc-gnustep --output=%t
+
+#import "objc/runtime.h"
+
+ at protocol NSCoding
+ at end
+
+#ifdef __has_attribute
+#if __has_attribute(objc_root_class)
+__attribute__((objc_root_class))
+#endif
+#endif
+ at interface NSObject <NSCoding> {
+ id isa;
+ int refcount;
+}
+ at end
+ at implementation NSObject
+- (id)class {
+ return object_getClass(self);
+}
++ (id)new {
+ return class_createInstance(self, 0);
+}
+ at end
+
+ at interface TestObj : NSObject {}
+- (int)ok;
+ at end
+ at implementation TestObj
+- (int)ok {
+ return self ? 0 : 1;
+}
+ at end
+
+// RUN: %lldb -b -o "b objc-gnustep-print.m:35" -o "run" -o "p self" -o "p *self" -- %t | FileCheck %s --check-prefix=SELF
+//
+// SELF: (lldb) b objc-gnustep-print.m:35
+// SELF: Breakpoint {{.*}} at objc-gnustep-print.m
+//
+// SELF: (lldb) run
+// SELF: Process {{[0-9]+}} stopped
+// SELF: -[TestObj ok](self=[[SELF_PTR:0x[0-9a-f]+]]{{.*}}) at objc-gnustep-print.m:35
+//
+// SELF: (lldb) p self
+// SELF: (TestObj *) [[SELF_PTR]]
+//
+// SELF: (lldb) p *self
+// SELF: (TestObj) {
+// SELF: NSObject = {
+// SELF: isa
+// SELF: refcount
+// SELF: }
+// SELF: }
+
+int main() {
+ TestObj *t = [TestObj new];
+ return [t ok];
+}
diff --git a/lldb/test/Shell/helper/build.py b/lldb/test/Shell/helper/build.py
index 55d871f2a0400..2c15d6df5149a 100755
--- a/lldb/test/Shell/helper/build.py
+++ b/lldb/test/Shell/helper/build.py
@@ -49,6 +49,18 @@
action='append',
help='If specified, a path to search in addition to PATH when --compiler is not an exact path')
+parser.add_argument('--objc-gnustep-dir',
+ metavar='directory',
+ dest='objc_gnustep_dir',
+ required=False,
+ help='If specified, a path to GNUstep libobjc2 runtime for use on Windows and Linux')
+
+parser.add_argument('--objc-gnustep',
+ dest='objc_gnustep',
+ action='store_true',
+ default=False,
+ help='Include and link GNUstep libobjc2 (Windows and Linux only)')
+
if sys.platform == 'darwin':
parser.add_argument('--apple-sdk',
metavar='apple_sdk',
@@ -238,6 +250,10 @@ def __init__(self, toolchain_type, args, obj_ext):
self.obj_ext = obj_ext
self.lib_paths = args.libs_dir
self.std = args.std
+ assert not args.objc_gnustep or args.objc_gnustep_dir, \
+ "--objc-gnustep specified without path to libobjc2"
+ self.objc_gnustep_inc = os.path.join(args.objc_gnustep_dir, 'include') if args.objc_gnustep_dir else None
+ self.objc_gnustep_lib = os.path.join(args.objc_gnustep_dir, 'lib') if args.objc_gnustep_dir else None
def _exe_file_name(self):
assert self.mode != 'compile'
@@ -656,15 +672,20 @@ def _get_compilation_command(self, source, obj):
args.append('-static')
args.append('-c')
- args.extend(['-o', obj])
- args.append(source)
-
if sys.platform == 'darwin':
args.extend(['-isysroot', self.apple_sdk])
+ elif self.objc_gnustep_inc:
+ if source.endswith('.m') or source.endswith('.mm'):
+ args.extend(['-fobjc-runtime=gnustep-2.0', '-I', self.objc_gnustep_inc])
+ if sys.platform == "win32":
+ args.extend(['-Xclang', '-gcodeview', '-Xclang', '--dependent-lib=msvcrtd'])
if self.std:
args.append('-std={0}'.format(self.std))
+ args.extend(['-o', obj])
+ args.append(source)
+
return ('compiling', [source], obj, None, args)
def _get_link_command(self):
@@ -686,6 +707,12 @@ def _get_link_command(self):
if sys.platform == 'darwin':
args.extend(['-isysroot', self.apple_sdk])
+ elif self.objc_gnustep_lib:
+ args.extend(['-L', self.objc_gnustep_lib, '-lobjc'])
+ if sys.platform == 'linux':
+ args.extend(['-Wl,-rpath,' + self.objc_gnustep_lib])
+ elif sys.platform == 'win32':
+ args.extend(['-fuse-ld=lld-link', '-g', '-Xclang', '--dependent-lib=msvcrtd'])
return ('linking', self._obj_file_names(), self._exe_file_name(), None, args)
diff --git a/lldb/test/Shell/helper/toolchain.py b/lldb/test/Shell/helper/toolchain.py
index 69b55b90751ac..c882223fb5d2f 100644
--- a/lldb/test/Shell/helper/toolchain.py
+++ b/lldb/test/Shell/helper/toolchain.py
@@ -42,6 +42,8 @@ def use_lldb_substitutions(config):
build_script_args.append('--tools-dir={0}'.format(config.lldb_tools_dir))
if config.llvm_libs_dir:
build_script_args.append('--libs-dir={0}'.format(config.llvm_libs_dir))
+ if config.objc_gnustep_dir:
+ build_script_args.append('--objc-gnustep-dir="{0}"'.format(config.objc_gnustep_dir))
lldb_init = _get_lldb_init_path(config)
diff --git a/lldb/test/Shell/lit.cfg.py b/lldb/test/Shell/lit.cfg.py
index 7717400f0de1b..20dd8fcc22769 100644
--- a/lldb/test/Shell/lit.cfg.py
+++ b/lldb/test/Shell/lit.cfg.py
@@ -24,7 +24,7 @@
# suffixes: A list of file extensions to treat as test files. This is overriden
# by individual lit.local.cfg files in the test subdirectories.
-config.suffixes = ['.test', '.cpp', '.s']
+config.suffixes = ['.test', '.cpp', '.s', '.m']
# excludes: A list of directories to exclude from the testsuite. The 'Inputs'
# subdirectories contain auxiliary inputs for various tests in their parent
@@ -135,6 +135,14 @@ def calculate_arch_features(arch_string):
if config.have_lldb_server:
config.available_features.add('lldb-server')
+if config.objc_gnustep_dir:
+ config.available_features.add('objc-gnustep')
+ if platform.system() == 'Windows':
+ # objc.dll must be in PATH since Windows has no rpath
+ config.environment['PATH'] = os.path.pathsep.join((
+ os.path.join(config.objc_gnustep_dir, 'lib'),
+ config.environment.get('PATH','')))
+
# NetBSD permits setting dbregs either if one is root
# or if user_set_dbregs is enabled
can_set_dbregs = True
diff --git a/lldb/test/Shell/lit.site.cfg.py.in b/lldb/test/Shell/lit.site.cfg.py.in
index d58918c873153..f84cb60ff9404 100644
--- a/lldb/test/Shell/lit.site.cfg.py.in
+++ b/lldb/test/Shell/lit.site.cfg.py.in
@@ -16,6 +16,7 @@ config.lldb_lit_tools_dir = lit_config.substitute(r"@LLDB_LIT_TOOLS_DIR@")
config.target_triple = "@LLVM_TARGET_TRIPLE@"
config.python_executable = "@Python3_EXECUTABLE@"
config.have_zlib = @LLVM_ENABLE_ZLIB@
+config.objc_gnustep_dir = "@LLDB_TEST_OBJC_GNUSTEP_DIR@"
config.lldb_enable_lzma = @LLDB_ENABLE_LZMA@
config.host_triple = "@LLVM_HOST_TRIPLE@"
config.lldb_bitness = 64 if @LLDB_IS_64_BITS@ else 32
More information about the lldb-commits
mailing list