Xcode project for Carthage support#55
Conversation
This adds an Xcode project to build OpenSSL frameworks. Carthage build
system relies exclusively on Xcode projects so adding one adds support
for building with Carthage.
The changes are based off 1.0.2.14 branch and do not use existing
support scripts. Unfortunately, I could not find a way to reuse them
(but that should be the right way). On the flip side, it's now possible
to build framworks using "xcodebuild" from command-line.
The project is configured as follows:
- Two targets "OpenSSL (iOS)" and "OpenSSL (macOS)" which build
Cocoa Touch and (desktop) Cocoa frameworks respectively. They
support iOS 8.0+ and macOS 10.9+.
- Each target has a corresponding Xcode scheme that builds it.
The schemes are *shared* which is required for Carthage to work.
- Both do not compile any new code and only combine prebuilt
binaries already present in the repository.
Some interesting caveats about configuration:
- Resulting frameworks are called "openssl.framework" for the sake
of compatibility with existing header include usage like
"#include <openssl/evp.h>" with all lowercase. This plays better
with so-called 'modular includes' that are necessary to use the
framework from Swift code.
- Umbrella headers "openssl.h" are compiled manually because
apparently inclusion order is important for OpenSSL. This is
important for Swift compiler, but mostly irrelevant to both
Swift and Objective-C users.
- In order to preserve the symbols from libssl.a and libcrypto.a
we use a custom linker flag "-all_load". It keeps the 'unused'
symbols from being removed by the linker (which is the default
behavior)
- Speaking of linker flags, the frameworks are explicitly *not*
code-signed. This is expected for frameworks which should be
signed only by the end-users (the application). Xcode does not
make it easy (even now), but it seems I got it right...
And that's probably it for the project configuration.
|
@krzyzanowskim Marcin please take a look :) We are not a Carthage-gurus ourselves, but start using it recently, so we believe that Carthage-OpenSSL will help to spread it among other projects. We've tested various combinations before submitting this PR, it works these ways:
|
What's in |
|
@krzyzanowskim Hm... I'm not sure that it's feasible to actually derive the correct inclusion order from headers. However, I think it will be okay to automate the way I compiled the headers manually:
This should work fine (at least for OpenSSL 1.0.2, I guess). |
It turns out that AppStore requires bundles to have strictly three-part semver-style versions. Replace "1.0.2.14" with "1.0.214" in the short identifier. Note that we have to keep the patch version in there because this is how the OS will decide on updates, so we have to keep it different and at least somewhat ordered.
|
@krzyzanowskim, as a side note, we have found that App Store is actually quite picky about framework bundle versions. I have pushed a commit that changes the bundle version from 1.0.2.14 to 1.0.214 (three components), because that's how Apple requires it to be. When you update to a newer OpenSSL this version has to be updated accordingly. |
It turns out that we cannot simply take all the headers and include them from the umbrella header. OpenSSL has some intricate interdependencies there so we have to resort to hacks. Instead of using "find" to locate all the headers (which returns them in some unspecified order), make sure to include the "ssl.h" header first and then follow it with other headers in alphabetic order. This seems to work for the current OpenSSL version (1.0.2o). Take care to not include the umbrella header into itself to avoid blowing up compiler's include stack.
|
@krzyzanowskim I have updated the create-framework.sh script to produce the same header includes as in the manual files. It grabs "ssl.h" first and then appends whatever else is there in the Headers directory. |
krzyzanowskim
left a comment
There was a problem hiding this comment.
Looks great thanks! I'm wondering, should we mention that in README.md as well?
|
Yeah, I guess it makes sense to drop a note about Carthage support in README. Something like this...InstallationCocoaPodsLatest stable version: Latest development version: CarthageLatest stable version: Latest development version: The 'stable' version will be broken for Carthage until a new tag is made (as I'm not sure how detailed that needs to be. I guess Carthage users should be able to figure out what needs to be done with their project to link against OpenSSL framework the way then need to. |
|
Anything in Installation section would be fine. It looks good. Do you want me to copy it, or will you PR? |
|
done e7e8d01 |
This adds an Xcode project to build OpenSSL frameworks. Carthage build system relies exclusively on Xcode projects so adding one adds support for building with Carthage. This is a modernized version of PR #27, and it should hopefully close the issue #31.
With this it is now possible to use OpenSSL via Carthage by putting the following line into Cartfile:
or, alternatively, with versions:
Then run
carthage updatewhich will download the source code and build the frameworks (or just download prebuilt binaries), and put them intoCarthagedirectory.Summary of changes
The changes are based off the 1.0.2.14 branch and do not use existing support scripts. Unfortunately, I could not find a way to reuse them from Xcode (but that should be the right way, probably). On the flip side, it's now possible to build framworks using
xcodebuildfrom command-line.Most of the changes are in Xcode XML stuff which is hard to review directly so I'll describe it here in more detail.
The project is configured as follows:
Two targets OpenSSL (iOS) and OpenSSL (macOS) which build Cocoa Touch and (desktop) Cocoa frameworks respectively. They support iOS 8.0+ and macOS 10.9+.
Each target has a corresponding Xcode scheme that builds it. The schemes are shared which is required for Carthage to work.
Both do not compile any new code and only combine prebuilt binaries already present in the repository.
Some interesting caveats about configuration:
Resulting frameworks are called openssl.framework for the sake of compatibility with existing header include usage like
#include <openssl/evp.h>with all lowercase. This plays better with so-called 'modular includes' that are necessary to use the framework from Swift code.Umbrella headers
openssl.hare compiled manually, because apparently inclusion order is important for OpenSSL. This is important for Swift compiler, but mostly irrelevant to both Swift and Objective-C users.In order to preserve the symbols from libssl.a and libcrypto.a we use a custom linker flag
-all_load. It keeps the 'unused' symbols from being stripped out by the linker (which is the default behavior for static libraries).Speaking of linker flags, the frameworks are explicitly not code-signed. This is expected for frameworks which should be signed only by the end-users (the application). Xcode does not make it easy (even now), but it seems I got it right...
And that's probably it for the project configuration.
How to maintain this
Making releases
Carthage relies on git tags for versioning. Therefore, tagging a release for OpenSSL will also release the new version of Carthage package. Currently there are no suitable tags (
1.0.2.14does not contain Xcode project). You would probably like to make a new one (say, 1.0.2.14.1) which will serve OpenSSL 1.0.2o to Carthage users. After that when you release a new version, just tag it as usual and it will be made accessible via Carthage.Prebuilt binaries
carthage build --archivewill produce a ZIP archive that can be attached to a GitHub release. This will allow the users to avoid compiling OpenSSL themselves. Depending on the bandwidth it may be quicker to download an archive than to compile it from scratch.Updating versions
It is also a good idea to keep the framework versions themselves in sync with the OpenSSL version. You can update them via Xcode here:
Note that iOS and macOS frameworks are separate, you have to update both targets. Also note that App Store requires the bundles to have three-component versions, therefore we use slightly weird scheme 1.0.214 (= 1.0.2 + 14, where 14 is the ordinal value of 'o', patch version of OpenSSL).
When updating OpenSSL version umbrella headers may need to be updated manually. You'll need to update the
Frameworks/{ios,macos}/openssl.hfiles so that they include all relevant headers frominclude-{ios,macos}/openssl. Headers from the a relevant directory should be included into the respective umbrella header.