johnxnguyen / Down

Blazing fast Markdown / CommonMark rendering in Swift, built upon cmark.
Other
2.24k stars 320 forks source link

[Carthage] Missing required module 'libcmark' #120

Closed AlexIzh closed 5 years ago

AlexIzh commented 5 years ago

Please help prevent duplicate issues before submitting a new one:

We had this issue for example project (https://github.com/iwasrobbed/Down/issues/57) but solution was related to only example project, but not all other cases.

Report

What did you do?

  1. Install the framework via carthage or manually to a project
  2. Move sources to another directory (remove/rename it). (For carthage - Carthage/Checkout, for manual installing - directory with sources)

What did you expect to happen?

The project is compiled and worked without any errors

What happened instead?

"Missing required module 'libcmark'" error is displayed.

Investigation Why does it happen? Seems like when a framework project contains a module with C code and as result a modulemap to this code, then result framework will contain links to the same C code with absolute paths. You can see that inside Down.framework/Modules/Down.swiftmodule/. Just open any swiftmodule file with any text editor and look for old modulemap path. I mean, this C code/headers(maybe just headers, not sure about that) should be placed at the same place for using the framework, otherwise framework won't find this C-module (in this case - cmark)

Workaround Only workaround what I've found is to copy cmark folder(folder with C code) inside your project (where you have to use Down.framework) and configure Import Paths to this directory. Then, when Down.framework have to find cmark module, it will use the project settings (module is configured and load to the project already). So, either do not remove Checkout directory for carthage (because framework will look for cmark module there) and as result do not use any caches for carthage (like rome), or add cmark directory to your project and configure Import Paths.

Bridging-Header solution If we remove using modulemap and add Bridging-Header to the project, then this case will work only when we don't have Checkouts folder. But at the same time, it won't work if sources are there (if you build it through carthage and do not remove Checkouts directory). In that case you will have Failed to import bridging header error when trying to build your project.

iwasrobbed commented 5 years ago

Hi there! I personally don't use Carthage so I can't be of much help with a fix. Maybe one of the other maintainers can advise here.

It might have to do with the modulemap file changing recently to remove the reference to the cmark include. Otherwise this project hasn't changed paths or file locations in a long time, so I'd be surprised if it broke because of that.

If you can reproduce this with an example project, that would also help others diagnose.

The goal is: this needs to work as a dynamic framework, a CocoaPods include and a Carthage include across all supported targets (macOS, iOS, tvOS

AlexIzh commented 5 years ago

That's not only related to carthage, but to any using .framework, like carthage, adding .framework manually to your project or something like that. It could not be reproduced with an example project, because there you insert link to Down project, not .framework file. So, framework will be created in compile the project phase and sources will be there too. I mean, it works, if you provide sources of cmark with your project/framework. If you build framework and put it to your project, but remove/move source of Down, then it will not work. For working with .framework file you have to have cmark sources either inside directory when it was build or inside your project + Import Paths.

If you do not use carthage, you can just build the framework, insert it to any other project and remove/move sources from which you have built that framework, you will get the same error

iwasrobbed commented 5 years ago

The example app integrates the framework manually by the way so I'm wondering why you say it doesn't work for you manually. Again, an example project would be helpful

AlexIzh commented 5 years ago

Example app doesn't integrate the framework file (Down.framework), there Down.project inserted inside example project. So, framework file will be created in compile phase and sources of cmark will be there too (not moved). If you do not want to store all sources of Down.project, then you should build Down.framework manually and put it to your project

iwasrobbed commented 5 years ago

Someone else will have to look into Carthage support, sorry there.

Re: integrating manually: Building a universal framework and linking the locations properly is not within the scope of this project. I would recommend just integrating the project so it builds a proper binary based upon the build target architecture

AlexIzh commented 5 years ago

https://github.com/iwasrobbed/Down/issues/57 The same problem, but solution just insert Down.project inside your project is not solution for all cases, because sometimes you have to just use .framework file without sources.

If using resulting framework file without sources is not within the scope of this project, then update README file:

carthage update --platform iOS

Or manually install:

Clone this repository
Build the Down project
Add the resulting framework file to your project
?
Profit

Both these installations are not working properly. Carthage is working only if you store Checkouts folders. Manually install working only if you either store sources of the project too or use it like subproject, but not resulting framework file.

Again, it is not related to carthage only. Just create framework file and use it with any project, then remove sources of Down project, you should be able to use .framework file then, but you can't.

iwasrobbed commented 5 years ago

@128keaton or @phoney Any insights here?

iwasrobbed commented 5 years ago

@AlexIzh Yes, the readme is wrong in that scenario. You can't just integrate a resulting .framework because it won't have all build slices needed for devices and simulators (aka it's not a fat binary or universal framework)

I believe Carthage pre-compiles into universal frameworks and then strips frameworks of simulator slices when archiving for the app store, so you'd have to do the same if you're doing things manually.

AlexIzh commented 5 years ago

@iwasrobbed you cannot use it not because of you don't have fat binary :) even if you create a fat binary yourselves, you won't be able to use this framework file without sources. if you try to remove sources, you will get the error from topic

iwasrobbed commented 5 years ago

I'd start with the modulemap and go from there. I am on vacation for the next 2 weeks so I don't have a computer to dig in.

Like I said earlier, this had to work for 4 different integration scenarios across 3 different target devices so if someone has a fix that doesn't break others, I'm happy to have a look

For now, I'd work around it until we can fix

ollieatkinson commented 5 years ago

For parties interested, I added the following as an xcconfig parameter to workaround the issue:

SWIFT_INCLUDE_PATHS = $(inherited) $(PROJECT_DIR)/Carthage/Checkouts/down/Source/cmark
nfgrilo commented 5 years ago

FTR, I can no longer reproduce this issue since the project I'm working on was upgraded to Swift 5.

iwasrobbed commented 5 years ago

Going to close this out as a Carthage integration detail. If someone has a fix that needs applying within this repo itself, feel free to open a pull request with it. Otherwise, this issue will act as docs for others

BrentMifsud commented 4 years ago

This also happens with Cocoapods Binary plugin.

I dont think this is specifically an issue with Carthage, but an issue with using Down as a .framework

kenmorse commented 3 years ago

I dont think this is specifically an issue with Carthage, but an issue with using Down as a .framework

Agreed; this seems to be an issue of relating specifically to the way cmark is pulled into the project.

erikkerber commented 3 years ago

For anyone interested – I have a branch that refactors the packaging of this framework a bit in a way that makes it portable, and obviates the need to add the cmark directory to the Swift includes path:

https://github.com/erikkerber/Down/tree/ek/portable-framework

It's a pretty early prototype that will work for me for now, which is all to say I haven't tested it hasn't broken anything with SPM. I used the technique described here, which involves making libcmark a submodule of Down.

Take note in my branch I also renamed the module DownLib because the module name was conflicting with the Down type in the generated swiftinterface when building with library evolution. The old "module name and type name are ambiguous" problem when using the fully qualified . syntax (which swiftinterface files do).