Skip to content

Commit c9f9350

Browse files
committed
[Compatibility50] Look up swift_getObjCClassMetadata at runtime.
This is the only dependency it has on libswiftCore. Looking this up at runtime allows its use in programs that don't link libswiftCore but might eventually load and run Swift code, such as xctest. While we're in there, enable tests in files ending with `.c`. rdar://problem/55274114
1 parent 813dfc4 commit c9f9350

File tree

4 files changed

+31
-5
lines changed

4 files changed

+31
-5
lines changed

stdlib/toolchain/Compatibility50/ProtocolConformance.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "Overrides.h"
2121
#include "../../public/runtime/Private.h"
2222
#include "swift/Basic/Lazy.h"
23+
#include <dlfcn.h>
2324
#include <mach-o/dyld.h>
2425
#include <mach-o/getsect.h>
2526
#include <objc/runtime.h>
@@ -89,13 +90,25 @@ static void registerAddImageCallback(void *) {
8990
_dyld_register_func_for_add_image(addImageCallback);
9091
}
9192

93+
static const Metadata *getObjCClassMetadata(const ClassMetadata *c) {
94+
// Look up swift_getObjCClassMetadata dynamically. This handles the case
95+
// where the main executable can't link against libswiftCore.dylib because
96+
// it will be loaded dynamically from a location that isn't known at build
97+
// time.
98+
using FPtr = const Metadata *(*)(const ClassMetadata *);
99+
FPtr func = SWIFT_LAZY_CONSTANT(
100+
reinterpret_cast<FPtr>(dlsym(RTLD_DEFAULT, "swift_getObjCClassMetadata")));
101+
102+
return func(c);
103+
}
104+
92105
// Clone of private helper swift::_swiftoverride_class_getSuperclass
93106
// for use in the override implementation.
94107
static const Metadata *_swift50override_class_getSuperclass(
95108
const Metadata *theClass) {
96109
if (const ClassMetadata *classType = theClass->getClassObject()) {
97110
if (classHasSuperclass(classType))
98-
return getMetadataForClass(classType->Superclass);
111+
return getObjCClassMetadata(classType->Superclass);
99112
}
100113

101114
if (const ForeignClassMetadata *foreignClassType

test/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ foreach(SDK ${SWIFT_SDKS})
205205

206206
# NOTE create a stub BlocksRuntime library that can be used for the
207207
# reflection tests
208-
file(WRITE ${test_bin_dir}/BlocksRuntime.c
208+
file(WRITE ${test_bin_dir}/Inputs/BlocksRuntime.c
209209
"void
210210
#if defined(_WIN32)
211211
__declspec(dllexport)
@@ -220,7 +220,7 @@ _Block_release(void) { }\n")
220220
ARCHITECTURE ${ARCH}
221221
SDK ${SDK}
222222
INSTALL_IN_COMPONENT dev
223-
${test_bin_dir}/BlocksRuntime.c)
223+
${test_bin_dir}/Inputs/BlocksRuntime.c)
224224
set_target_properties(BlocksRuntimeStub${VARIANT_SUFFIX} PROPERTIES
225225
ARCHIVE_OUTPUT_DIRECTORY ${test_bin_dir}
226226
LIBRARY_OUTPUT_DIRECTORY ${test_bin_dir}

test/lit.cfg

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,8 @@ config.test_format = swift_test.SwiftTest(coverage_mode=config.coverage_mode,
178178
execute_external=not use_lit_shell)
179179

180180
# suffixes: A list of file extensions to treat as test files.
181-
config.suffixes = ['.swift', '.ll', '.sil', '.gyb', '.m', '.swiftinterface',
182-
'.test-sh']
181+
config.suffixes = ['.swift', '.ll', '.sil', '.gyb', '.m', '.c',
182+
'.swiftinterface', '.test-sh']
183183

184184
# excludes: A list of directories to exclude from the testsuite. The 'Inputs'
185185
# subdirectories contain auxiliary inputs for various tests in their parent

test/stdlib/Compatibility50Linking.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-clang %s -all_load %test-resource-dir/%target-sdk-name/libswiftCompatibility50.a -lobjc -o %t/main
3+
// RUN: %target-run %t/main
4+
// REQUIRES: objc_interop
5+
// REQUIRES: executable_test
6+
7+
// The compatibility library needs to have no build-time dependencies on
8+
// libswiftCore so it can be linked into a program that doesn't link
9+
// libswiftCore, but will load it at runtime, such as xctest.
10+
//
11+
// Test this by linking it into a plain C program and making sure it builds.
12+
13+
int main(void) {}

0 commit comments

Comments
 (0)