Module not found for xcframework dependency with static Swift libraries inside
viktorsimko-rev opened this issue · 16 comments
I'm trying to add an xcframework dependency containing static Swift libraries which looks something like this:
├── Info.plist
├── ios-arm64
│ ├── SomeLibrary.swiftmodule
│ └── libSomeLibrary.a
└── ios-arm64_x86_64-simulator
├── SomeLibrary.swiftmodule
└── libSomeLibrary.a
So as you can see it just contains a .switmodule
and the static archive.
Currently the import target for this is created here in the third branch (("static", "library")
) in library.bzl
:
if (linkage, packaging) == ("dynamic", "framework"):
apple_dynamic_framework_import(
name = resolved_target_name,
framework_imports = native.glob(
[path + "/**/*"],
exclude = ["**/.DS_Store"],
),
deps = [],
dsym_imports = dsym_imports,
tags = _MANUAL,
)
elif (linkage, packaging) == ("static", "framework"):
apple_static_framework_import(
name = resolved_target_name,
framework_imports = native.glob(
[path + "/**/*"],
exclude = ["**/.DS_Store"],
),
deps = [],
tags = _MANUAL,
)
elif (linkage, packaging) == ("static", "library"):
native.objc_import(
name = resolved_target_name,
archives = [path],
tags = _MANUAL,
)
else:
fail("Unsupported xcframework slice type {} ({}) in {}".format(
build_type,
identifier,
xcframework_name,
))
It uses native.objc_import
which doesn't expose the Swift module, so it won't be found compile time by the dependent targets.
If I create a rule for exposing the module using a SwiftInfo
provider it solves the issue:
def _swift_import_impl(ctx):
providers = [dep[CcInfo] for dep in ctx.attr.deps]
providers += [dep[apple_common.Objc] for dep in ctx.attr.deps]
return providers + [
swift_common.create_swift_info(
modules = [
swift_common.create_module(
name = ctx.attr.name,
swift = swift_common.create_swift_module(
swiftdoc = None,
swiftmodule = ctx.file.swiftmodule,
)
)
]
)
]
swift_import = rule(
implementation = _swift_import_impl,
attrs = {
"swiftmodule": attr.label(allow_single_file = True),
"deps": attr.label_list(default = [])
}
)
usage of the rule in the above included code snippet from library.bzl
:
elif (linkage, packaging) == ("static", "library"):
libdir = path.rpartition("/")[0]
native.objc_import(
name = resolved_target_name + "_objc_import",
archives = [path],
tags = _MANUAL,
)
swift_import(
name = resolved_target_name,
swiftmodule = native.glob([libdir + "/**/*.swiftmodule"], exclude_directories = 0)[0],
deps = [resolved_target_name + "_objc_import"]
)
Do you know of an already existent solution for this? Am I missing something?
There's a similar issue with missing headers for Objective C static libraries within xcframeworks: https://**/archives/CRPRV58UF/p1659897884759499
I plan on creating a reproducible example this week so we can add support / fix the issues here.
Might be the case this setup is not currently supported.
Yep it looks like giving rules_ios a library based framework needs a number of fixes. I think what you've got here: globbing for the same inputs adjacent to the .a
is a fine way to add it.
@viktorsimko-rev thanks again for the issue - what it looks like is this case is basically not handled yet: a .xcframework
with .a
s in it.
@luispadron @jerrymarino thank you for looking into this!
@viktorsimko-rev Would you happen to know how to create a .swiftmodule
when archiving a static library via Xcode? I've got my PR up fixing these issues for Objective-C but my archives don't contain an .swiftmodule for use within Swift frameworks
@luispadron it creates a .swiftmodule
by default for Static Library targets. (If it's Swift only at least)
@luispadron sorry, I'm a bit sleepy, it creates it but then doesn't include it in the archive indeed.
I think the only option here might be just building it and not archiving.
You've got it - would be great if we can get this working 👍
@luispadron I'm not sure about how to actually create one of these off hand in Xcode - if there is anything close to a public or canonical specification of what this code should do it'd probably be in the SPM code. I would suggest to look there, or see if there is an easy way to create one from there.
Ingesting vendor binaries into rules_ios created by SPM ( and Xcode ) is a highly reasonable use case. You can also reach out to the vendor in question ( or if they have code on github ) about how it was created.
@jerrymarino @luispadron
I've found this: apple/swift-package-manager#2981 (comment)
Here Boris copies the .swiftmodule
from derived data into the archive.
So I checked derived data using the link you posed @viktorsimko-rev and I'm still not seeing a .swiftmodule
└── Release-iphoneos
└── libLoggerStaticLib.a
It only has the .a
file and now .swiftmodule
anywhere in the derived data folder. From the issue you linked it looks like this requires a framework, and not a static library to work.. Going to see if we can wrap it in a framework somehow. Truly, love how undocumented all of these Apple formats are.
@luispadron That's weird, because it's there for me:
Release-iphonesimulator
├── TestLib.swiftmodule
│ ├── Project
│ │ ├── arm64-apple-ios-simulator.swiftsourceinfo
│ │ ├── arm64.swiftsourceinfo
│ │ ├── x86_64-apple-ios-simulator.swiftsourceinfo
│ │ └── x86_64.swiftsourceinfo
│ ├── arm64-apple-ios-simulator.swiftdoc
│ ├── arm64-apple-ios-simulator.swiftinterface
│ ├── arm64-apple-ios-simulator.swiftmodule
│ ├── arm64.swiftdoc
│ ├── arm64.swiftinterface
│ ├── arm64.swiftmodule
│ ├── x86_64-apple-ios-simulator.swiftdoc
│ ├── x86_64-apple-ios-simulator.swiftinterface
│ ├── x86_64-apple-ios-simulator.swiftmodule
│ ├── x86_64.swiftdoc
│ ├── x86_64.swiftinterface
│ └── x86_64.swiftmodule
└── libTestLib.a
Could you post the project here? I can take it and update the fixture in the PR.
Of course, here it is: https://github.com/viktorsimko-rev/TestLib
Oh I see this just a pure Swift project, thats fine, will use this to add an extra fixture on-top of the Objective-C one I made. There are two issues with static library handling from what I can tell
- rules_ios doesn't use the
.swiftmodule
included with the static library (this issue) - rules_ios doesnt use the
Headers
included with the static library
@viktorsimko-rev I've updated #530 to include a Swift fixture static library xcframework. I'm focused on fixing the Objective-C use case right now but if you already have a working solution for the Swift one please feel free to push changes to that PR / branch from there!
@luispadron The solution I currently have does not yet work with import middleman or vfs, but I will try to see what can I do with those, I just don't know how much time I'm going to have in the upcoming days for that.