I have a simple framework example I wrote to show the problem. It consists of an Objective-C based framework "Hello" with the class "Hello", with a swift file "Something.swift", and a modulemap "hello.modulemap".
In the project, I have 2 targets:
- Hello, a dynamic framework
- HelloStatic, a static library
In the build settings, I've set:
- Build Libraries for Distribution = Yes
- Module Identifier = Hello
- Defines Module = Yes
- Module Map File = $(SRCROOT)/Hello/hello.modulemap
- Product Module Name = Hello
- Enable Clang Module Debugging = Yes
- Enable Modules (C and Objective C) = Yes
- Objective-C Generated Interface Header Name = Hello-Swift.h
- Swift Language Version = Swift 5
For the HelloStatic target, I've tried both Hello and HelloStatic as the Product Name, leaving the Product Module Name = Hello (because I don't want to have to change the import statement depending on whether I consume the dynamic framework or the static library.)
The Mach-O type for the targets is Dynamic Library and Static Library respectively.
The Issue:
- If I build the target Hello, everything works fine as expected. The swift file recognizes the modulemap, and the extension for Hello works as expected.
- If I build the target HelloStatic, the swift file tells me: Cannot find type 'Hello' in scope on the line with the 'extension Hello'
If I disable Build Libraries for Distribution, then I can add a Bridging-Header file which does an #import "Hello.h"
and the build succeeds, but it doesn't generate the Hello-Swift.h header, nor the *.swiftinterface files needed to consume a Swift library any another App.
I figure that the compiler is either ignoring the modulemap file, or doesn't find it in it's search paths.
Help!
Since the dynamic library builds just fine, there has to be a solution to create a static library.
I almost forgot: If I swap out the 'extension Hello'
with 'public class Goodbye',
then I am able to build both the dynamic framework and the static library just fine, because my Swift module doesn't explicitly use "Hello" directly. (That is the reason for using the Selector mechanism, for those who were wondering).
If I didn't use the Selector mechanism, then everywhere I try to use the Hello class in my Swift file I would get an error when building the static library. However, if I want to call the Objective-C text: function I would use Hello.text in my App, but would have to use Goodbye.Text to call the function in the Swift module, and I don't want to do that. I want to be able to use Hello.Text like I can when I have a dynamic framework, when I use the Static Library as a framework.
The full project can be found at: https://github.com/reststop/Hello
Any help would be appreciated. I've scoured the forums and tried almost everything that looked like it might help. I may even be willing to pay a small bounty, as I've spent over a week on this and have come up empty. (working on a full-fledged Library -- I distilled this to show the issue).
Hello.h
//
// Hello.h
//
#import <Foundation/Foundation.h>
FOUNDATION_EXPORT double HelloVersionNumber;
FOUNDATION_EXPORT const unsigned char HelloVersionString[];
@interface Hello : NSObject
+ (void)initWithSub:(NSString*)sub uid:(NSString*)uid;
+ (void)text:(NSString *)string;
@end
Hello.m
//
// Hello.m
//
#import "Hello.h"
@interface Hello ()
@end
@implementation Hello
static NSString *mySub;
static NSString *myUid;
+ (void)initWithSub:(NSString*)sub uid:(NSString*)uid {
mySub = sub;
myUid = uid;
NSLog(@"Initialize: sub( %@ ), uid( %@ )", sub, uid);
}
+ (void)text:(NSString *)string {
NSLog(@"Text in Objc: %@", string);
}
@end
Smething.swift
//
// Something.swift
//
import Foundation
// Use one of the following:
//class
//public class Goodbye {
//extension
//public extension Hello {
public extension Hello {
public class func Text(_ text: String) {
if let hello = NSClassFromString("Hello") {
let selector: Selector = NSSelectorFromString("text:")
if hello.responds(to: selector) {
debugPrint("Swift calling \(selector) \(text)")
hello.perform(selector, with: text as NSString, afterDelay: 0)
}
}
}
} // end of class or extension
Hello.modulemap
framework module Hello {
umbrella header "Hello.h"
export *
module * { export * }
}