Xcodegen: Better static library support

Created on 19 Jul 2018  ยท  6Comments  ยท  Source: yonaskolb/XcodeGen

Static libraries that are used by other targets in the same project/workspace have some conventions that need be followed that Xcode doesn't easily provide by default:

  • Need to have a Copy Files phase for all public headers

    • Needs to include a PRODUCT_NAME-Swift.h if it's a Swift library and it's going to be consumed by Objective-C.

    • Needs to include a modulemap if it's going to be @imported in Objective-C, or if it's an Objective-C library going to be imported into Swift.

  • Need to only link to the final executable to prevent duplicate symbols.

    • If the code includes Objective-C categories (or Swift extensions on Objective-C classes) it needs to be linked with -ObjC or the linker will drop those symbols.

  • Need to not link against other libraries or frameworks (else https://github.com/CocoaPods/CocoaPods/issues/7251 like warnings happen)
  • Need to have SKIP_INSTALL set to YES to prevent an invalid archive.

Here are my plans for how we can improve the use of static libraries with XcodeGen to address the above requirements:

  1. โœ… static.library targets will copy (#345) headers in Sources with public headerVisibility to include/$(PRODUCT_NAME) in the Products Directory, as long as the buildPhase is headers or not specified. โ€“ #365
    i. If any Swift files are included in Sources, and SWIFT_OBJC_INTERFACE_HEADER_NAME is not an empty string, the Swift-ObjC Interface Header will be copied to the same location with a script. โ€“ #366
    ii. โœ… To support modules a module.modulemap will need to be manually supplied. If it's included in Sources it will be copied to the same location. โ€“ #346 (_I need to see if there is a way to manually generate this similar to how Xcode does for frameworks. I also need to see if we need to set MODULEMAP_FILE, since I haven't needed to yet._)

  2. If a target dependency of type static.library is declared for a target:

    1. โœ… link will default to true only for isExecutable targets. If a dynamic framework needs to link against a static library (maybe to create a wrapper) the default can be changed. โ€“ #352
    2. โœ… A new requiresObjCLinking property on
      Target, if true, will add -ObjC to OTHER_LDFLAGS for targets that link against it. It will default to true if type is library.static. โ€“ #353
    3. โœ… If transitivelyLinkDependencies is true static libraries will now propagate. โ€“ #352
  3. โœ… static.library targets won't link against any library or frameworks, unless link is manually set to true. โ€“ #352
  4. โœ… Will add a library.static.yml to SettingsPresets/Product/ with SKIP_INSTALL set to YES. โ€“ #358
enhancement

Most helpful comment

For us we don't set this per target, we set it in xcconfigs.

I believe @yonaskolb mentioned that XcodeGen can read the resolved settings, even if set from xcconfigs?

Edit: Here is where he said that: https://github.com/yonaskolb/XcodeGen/pull/327#issuecomment-401651936

All 6 comments

@Keith Since you have way more static library experience than I do, can you give this a look over to make sure I didn't get anything wrong or miss anything? Thanks!

Looks right to me. I'm not sure about adding the build script for copying the header, that seems pretty invasive to me, but I'm not sure how that stuff fits together since we have 0 Objective-C, so we haven't had this problem (and we don't even generate these headers)

(I need to confirm that linking against extensions and hosted tests is desired.)

This is desired, although can lead to more copies of the static library in your final .app if you have extensions and apps that depend on the same libraries. This is a trade off we've decided to make vs taking the launch overhead of dynamic link time.

I'm not sure about adding the build script for copying the header, that seems pretty invasive to me, but I'm not sure how that stuff fits together since we have 0 Objective-C, so we haven't had this problem

Yeah, we have Objective-C. And setting up an Objective-C project in Xcode copies public headers by default, all the guides on how to create Objective-C static libraries mention the same, and I needed to do it locally to make it work. I'm not sure how to make it "configurable", if desired.

(and we don't even generate these headers)

I'm pretty sure you always generate the -Swift.h header file. It should be located at $(DERIVED_SOURCES_DIR)/$(SWIFT_OBJC_INTERFACE_HEADER_NAME). If you set SWIFT_OBJC_INTERFACE_HEADER_NAME to an empty string does it prevent it from being generated? (I could use that as a way to not generate that step)

If you set SWIFT_OBJC_INTERFACE_HEADER_NAME to an empty string does it prevent it from being generated?

Exactly.

(I could use that as a way to not generate that step)

Might be tough for some configurations. For us we don't set this per target, we set it in xcconfigs.

For us we don't set this per target, we set it in xcconfigs.

I believe @yonaskolb mentioned that XcodeGen can read the resolved settings, even if set from xcconfigs?

Edit: Here is where he said that: https://github.com/yonaskolb/XcodeGen/pull/327#issuecomment-401651936

@yonaskolb I'm working on 1.i above and should have a PR soon. I would like to get that in before we cut our next release (so one released has all the static library stuff in it).

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pvinis picture pvinis  ยท  6Comments

ImLaufderZeit picture ImLaufderZeit  ยท  5Comments

vlozko picture vlozko  ยท  4Comments

rpassis picture rpassis  ยท  5Comments

mohammdsss1 picture mohammdsss1  ยท  6Comments