Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(Frameworks): set Header Target Membership 'type' to Public || Private || Project #222

Closed
sstadelman opened this issue Dec 16, 2014 · 9 comments

Comments

@sstadelman
Copy link

I am trying to set the Target Membership 'type' to Public, for headers which should be made public in an iOS Framework. I have a script which adds classes to the project and target, and I can successfully build and utilize the framework classes, after switching this value manually.

This may be currently possible via the PBXBuildFile #settings instance attribute, but I don't see the (seemingly) correct values taking effect.

The Xcode UI shortcut is located here. Note that I've already switched the value from "Project" to "Public" on the Booking.h class".
image

This is logically equivalent to moving the headers between the "Project" (default), "Private", and "Public" sections in the Target > Build Phases > Headers menu.
image

I've been trying to use the PBXBuildFile and PBXHeaderBuildPhase to set this value, with no success, as follows:

for i in 0..target.headers_build_phase.files.length - 1
    build_file = target.headers_build_phase.files[i]
    build_file.settings = { 'Attributes' => ['Public']}
    logger.info build_file.pretty_print
end

outputs:

INFO  : <Hash> {"Booking.h"=>{"Attributes"=>["Public"]}}
INFO  : <Hash> {"Carrier.h"=>{"Attributes"=>["Public"]}}
INFO  : <Hash> {"Flight.h"=>{"Attributes"=>["Public"]}}
INFO  : <Hash> {"Flight_DQ.h"=>{"Attributes"=>["Public"]}}
INFO  : <Hash> {"Notification.h"=>{"Attributes"=>["Public"]}}
INFO  : <Hash> {"Subscription.h"=>{"Attributes"=>["Public"]}}
INFO  : <Hash> {"Travelagency.h"=>{"Attributes"=>["Public"]}}
INFO  : <Hash> {"Travelagency_DQ.h"=>{"Attributes"=>["Public"]}}
INFO  : <Hash> {"ODataModel.h"=>{"Attributes"=>["Public"]}}

I've also tried initializing the PBXBuildFile directly on the Project + PBXFileReference, but do not see a method for adding it to the target references.

ref = classes_group.files[i]
if ref.last_known_file_type == 'sourcecode.c.h'
    reusable_build_settings = Xcodeproj::Project::PBXBuildFile.new(ref, { 'Attributes' => 'Public'})
end
target.add_file_references([ref])

It seems that the API for this value should be on PBXFileReference, or PBXBuildFile. Does anyone know if this is available?

@sstadelman
Copy link
Author

I dug-in to the project.pbxproj, and can confirm that the attributes do indeed belong to the PBXBuildFile.

From the top of the document (see Booking.h):

/* Begin PBXBuildFile section */
        1EA15DA9E3D2229FCFB8A5A4 /* Subscription.h in Headers */ = {isa = PBXBuildFile; fileRef = 6BD914C278780DFB284B2A70 /* Subscription.h */; };
        2B4537635836AC65A58E80F0 /* Flight.h in Headers */ = {isa = PBXBuildFile; fileRef = 51FF7CF6902EFB9FC7D9786B /* Flight.h */; };
        499FC07D2FE1D596DEE29CB4 /* Flight.m in Sources */ = {isa = PBXBuildFile; fileRef = 409BD7265FB210B03E063BC8 /* Flight.m */; };
        4F21A1CEBD536D5E262CED2B /* Travelagency.h in Headers */ = {isa = PBXBuildFile; fileRef = 6BC374706D41326D80462166 /* Travelagency.h */; };
        57471E42259826A02C7A885F /* Travelagency_DQ.h in Headers */ = {isa = PBXBuildFile; fileRef = B04D4BCFAA4C3DB59D4C88A6 /* Travelagency_DQ.h */; };
        5FBDB559F0AF63E33BB7350B /* Booking.m in Sources */ = {isa = PBXBuildFile; fileRef = 759325A35EE922335CD8DC89 /* Booking.m */; };
        68B26DDD7051A26EEC70ABD9 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04F2E431CFB8C518F21E25C2 /* Foundation.framework */; };
        731F3EE928FEB3CF57539C76 /* Subscription.m in Sources */ = {isa = PBXBuildFile; fileRef = A97521E539FB29D483669FFE /* Subscription.m */; };
        A76A2826F49672CEF95C232D /* Flight_DQ.h in Headers */ = {isa = PBXBuildFile; fileRef = BF2C7DFD6051C25EB7EF3DCC /* Flight_DQ.h */; };
        B8A1455BEB91A9FEF7793BFF /* Travelagency.m in Sources */ = {isa = PBXBuildFile; fileRef = 69B2FD0A7A80768D0E8AC23E /* Travelagency.m */; };
        B9DFACA6868528F7543BD385 /* ODataModel.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A2CB035F21E3A99A4F92AE3 /* ODataModel.h */; };
        C071239A9E3E2A0B0690082C /* Notification.m in Sources */ = {isa = PBXBuildFile; fileRef = 92AF8A6B853BFD9F6CB0E785 /* Notification.m */; };
        C2FC476373EA94812A122E1E /* Booking.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E51C826C430239C7873CCBF /* Booking.h */; settings = {ATTRIBUTES = (Public, ); }; };
        C36E7301E1ED9C9D713DFE03 /* Notification.h in Headers */ = {isa = PBXBuildFile; fileRef = 21EE7DC3C60097C3E1AE85AD /* Notification.h */; };
        DFC17AF8F54298380A4E547F /* Carrier.h in Headers */ = {isa = PBXBuildFile; fileRef = 287C9C941B04BA0F161E8440 /* Carrier.h */; };
        F3710F70AC77463B334A3A91 /* Flight_DQ.m in Sources */ = {isa = PBXBuildFile; fileRef = 838F079902379B594C3E1A27 /* Flight_DQ.m */; };
        F67D776F4BBDC0CD36E59E04 /* Carrier.m in Sources */ = {isa = PBXBuildFile; fileRef = 06235992AD6B2835E573B256 /* Carrier.m */; };
        FFFD7FF05B78EA5D4FAE7F4A /* Travelagency_DQ.m in Sources */ = {isa = PBXBuildFile; fileRef = EACA91744223CFA1832E52CF /* Travelagency_DQ.m */; };
/* End PBXBuildFile section */

So, I tried brute-forcing the edit of the settings value on each build file. I iterated through each item in the project objects list. If the file was a PBXBuildFile, I set the settings = { 'Attributes' => ['Public']}. Then, I saved the project.

for i in 0..proj.objects.length - 1
    obj = proj.objects[i]
    if obj.class == Xcodeproj::Project::PBXBuildFile
        build_file = obj;
        build_file.settings = { 'Attributes' => ['Public']}
        proj.save
    end
    logger.info obj.uuid
    logger.debug obj.pretty_print
end

I can see that the UUID's of the PBXBuildFile's match those in the project.pbxproj, and the logger output shows that the settings of the build files have been set; but, they do not appear to be written to the *.pbxproj.

 INFO  testing_logger : C2FC476373EA94812A122E1E
DEBUG  testing_logger : <Hash> {"Booking.h"=>{"Attributes"=>["Public"]}}
 INFO  testing_logger : 5FBDB559F0AF63E33BB7350B
DEBUG  testing_logger : <Hash> {"Booking.m"=>{"Attributes"=>["Public"]}}
 INFO  testing_logger : DFC17AF8F54298380A4E547F
DEBUG  testing_logger : <Hash> {"Carrier.h"=>{"Attributes"=>["Public"]}}
 INFO  testing_logger : F67D776F4BBDC0CD36E59E04
DEBUG  testing_logger : <Hash> {"Carrier.m"=>{"Attributes"=>["Public"]}}
 INFO  testing_logger : 2B4537635836AC65A58E80F0
DEBUG  testing_logger : <Hash> {"Flight.h"=>{"Attributes"=>["Public"]}}
 INFO  testing_logger : 499FC07D2FE1D596DEE29CB4
DEBUG  testing_logger : <Hash> {"Flight.m"=>{"Attributes"=>["Public"]}}
 INFO  testing_logger : A76A2826F49672CEF95C232D
DEBUG  testing_logger : <Hash> {"Flight_DQ.h"=>{"Attributes"=>["Public"]}}
 INFO  testing_logger : F3710F70AC77463B334A3A91
DEBUG  testing_logger : <Hash> {"Flight_DQ.m"=>{"Attributes"=>["Public"]}}
 INFO  testing_logger : C36E7301E1ED9C9D713DFE03
DEBUG  testing_logger : <Hash> {"Notification.h"=>{"Attributes"=>["Public"]}}
 INFO  testing_logger : C071239A9E3E2A0B0690082C
DEBUG  testing_logger : <Hash> {"Notification.m"=>{"Attributes"=>["Public"]}}
 INFO  testing_logger : 1EA15DA9E3D2229FCFB8A5A4
DEBUG  testing_logger : <Hash> {"Subscription.h"=>{"Attributes"=>["Public"]}}
 INFO  testing_logger : 731F3EE928FEB3CF57539C76
DEBUG  testing_logger : <Hash> {"Subscription.m"=>{"Attributes"=>["Public"]}}
 INFO  testing_logger : 4F21A1CEBD536D5E262CED2B
DEBUG  testing_logger : <Hash> {"Travelagency.h"=>{"Attributes"=>["Public"]}}
 INFO  testing_logger : B8A1455BEB91A9FEF7793BFF
DEBUG  testing_logger : <Hash> {"Travelagency.m"=>{"Attributes"=>["Public"]}}
 INFO  testing_logger : 57471E42259826A02C7A885F
DEBUG  testing_logger : <Hash> {"Travelagency_DQ.h"=>{"Attributes"=>["Public"]}}
 INFO  testing_logger : FFFD7FF05B78EA5D4FAE7F4A
DEBUG  testing_logger : <Hash> {"Travelagency_DQ.m"=>{"Attributes"=>["Public"]}}
 INFO  testing_logger : B9DFACA6868528F7543BD385
DEBUG  testing_logger : <Hash> {"ODataModel.h"=>{"Attributes"=>["Public"]}}

@orta
Copy link
Member

orta commented Dec 16, 2014

This was what I did to set a file to be a public header in a framework in a project using xcodeproj, https://github.com/orta/cocoapods-keys/blob/master/lib/installer.rb#L42-L47

@sstadelman
Copy link
Author

@orta Thanks! this solved the issue. I think I was failing to uppercase the complete "ATTRIBUTES" string.

# works
target.headers_build_phase.files[-1].settings = { "ATTRIBUTES" => ["Public"] }
#fails
target.headers_build_phase.files[-1].settings = { "Attributes" => ["Public"] }

@sstadelman
Copy link
Author

@orta Is there a documentation location where I could post some code samples for this and some similar topics?

@orta
Copy link
Member

orta commented Dec 16, 2014

Nope, IMO, I'd love something like this, as I also just had to iterate a bunch of times till I found the answer.

@AliSoftware
Copy link
Contributor

I thought this "Header" Build Phase was officially recognized broken and obsolete by Apple, and that they suggest to use the "Copy Files" Build Phase instead?
➡️ Source: Apple TechNote

Or is it only with static libraries and not frameworks? Or maybe they did fix that since Xcode 6?

@neonichu
Copy link
Member

@AliSoftware when creating a framework manually using Xcode and changing the visibility of a header from the inspector, they end up in the "Headers" build phase, so I think this was either fixed or did never apply to frameworks in the first place.

@revolter
Copy link
Contributor

Couldn't PBXHeadersBuildPhase overwrite the add_file_reference method to add a visibility parameter so you could do:

framework_target.headers_build_phase.add_file_reference(file_reference, 'Public')

?

@emysa341
Copy link

emysa341 commented Oct 1, 2018

For me the following script worked posted by @sstadelman , I changed 'Attributes' -> 'ATTRIBUTES'

for i in 0..proj.objects.length - 1 obj = proj.objects[i] if obj.class == Xcodeproj::Project::PBXBuildFile build_file = obj; build_file.settings = { 'ATTRIBUTES' => ['Public']} proj.save end logger.info obj.uuid logger.debug obj.pretty_print end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants