Mục tiêu-C trong thư viện tĩnh


153

Bạn có thể hướng dẫn tôi cách liên kết đúng thư viện tĩnh với dự án iPhone không. Tôi sử dụng dự án thư viện tĩnh được thêm vào dự án ứng dụng làm phụ thuộc trực tiếp (đích -> chung -> phụ thuộc trực tiếp) và tất cả đều hoạt động tốt, nhưng các danh mục. Một thể loại được xác định trong thư viện tĩnh không hoạt động trong ứng dụng.

Vì vậy, câu hỏi của tôi là làm thế nào để thêm thư viện tĩnh với một số loại vào dự án khác?

Và nói chung, cách tốt nhất để sử dụng trong mã dự án ứng dụng từ các dự án khác là gì?


1
tốt, tìm thấy một số câu trả lời và có vẻ như câu hỏi này đã được trả lời ở đây (xin lỗi đã bỏ lỡ stackoverflow.com/questions/932856/ mẹo )
Vladimir

Câu trả lời:


227

Giải pháp: Kể từ Xcode 4.2, bạn chỉ cần truy cập ứng dụng đang liên kết với thư viện (không phải chính thư viện) và nhấp vào dự án trong Project Navigator, nhấp vào mục tiêu của ứng dụng, sau đó xây dựng cài đặt, sau đó tìm kiếm "Khác Cờ liên kết ", nhấp vào nút + và thêm '-ObjC'. '-all_load' và '-force_load' không còn cần thiết nữa.

Chi tiết: Tôi tìm thấy một số câu trả lời trên các diễn đàn, blog và tài liệu táo khác nhau. Bây giờ tôi thử thực hiện tóm tắt ngắn về các tìm kiếm và thử nghiệm của tôi.

Vấn đề được gây ra bởi (trích dẫn từ apple Q & A QA1490 https://developer.apple.com/l Library / content / qa / qa1490 / _index.html ):

Objective-C không định nghĩa các ký hiệu liên kết cho từng chức năng (hoặc phương thức, trong Objective-C) - thay vào đó, các ký hiệu liên kết chỉ được tạo cho mỗi lớp. Nếu bạn mở rộng một lớp có sẵn với các danh mục, trình liên kết không biết liên kết mã đối tượng của việc triển khai lớp lõi và thực hiện danh mục. Điều này ngăn các đối tượng được tạo trong ứng dụng kết quả phản hồi lại bộ chọn được xác định trong danh mục.

Và giải pháp của họ:

Để giải quyết vấn đề này, thư viện tĩnh phải chuyển tùy chọn -ObjC cho trình liên kết. Cờ này làm cho trình liên kết tải mọi tệp đối tượng trong thư viện xác định lớp hoặc loại Objective-C. Mặc dù tùy chọn này thường dẫn đến một tệp thực thi lớn hơn (do mã đối tượng bổ sung được tải vào ứng dụng), nhưng nó sẽ cho phép tạo thành công các thư viện tĩnh Objective-C hiệu quả có chứa các danh mục trên các lớp hiện có.

và cũng có khuyến nghị trong Câu hỏi thường gặp về Phát triển iPhone:

Làm cách nào để liên kết tất cả các lớp Objective-C trong một thư viện tĩnh? Đặt cài đặt xây dựng Cờ liên kết khác thành -ObjC.

và mô tả cờ:

- all_load Tải tất cả các thành viên của thư viện lưu trữ tĩnh.

- ObjC Tải tất cả các thành viên của các thư viện lưu trữ tĩnh thực hiện một lớp hoặc thể loại Objective-C.

- force_load (path_to_archive) Tải tất cả các thành viên của thư viện lưu trữ tĩnh được chỉ định. Lưu ý: -all_load buộc tất cả các thành viên của tất cả các tài liệu lưu trữ được tải. Tùy chọn này cho phép bạn nhắm mục tiêu một kho lưu trữ cụ thể.

* chúng tôi có thể sử dụng force_load để giảm kích thước nhị phân của ứng dụng và để tránh xung đột mà all_load có thể gây ra trong một số trường hợp.

Có, nó hoạt động với các tệp * .a được thêm vào dự án. Tuy nhiên, tôi đã gặp rắc rối với dự án lib được thêm vào như là phụ thuộc trực tiếp. Nhưng sau đó tôi thấy rằng đó là lỗi của tôi - dự án phụ thuộc trực tiếp có thể không được thêm đúng. Khi tôi gỡ bỏ nó và thêm lại với các bước:

  1. Kéo và thả tập tin dự án lib trong dự án ứng dụng (hoặc thêm nó bằng Project-> Thêm vào dự án).
  2. Nhấp vào mũi tên tại biểu tượng dự án lib - tên tệp mylib.a được hiển thị, kéo tệp mylib.a này và thả nó vào Target -> Link Binary With Library group.
  3. Mở thông tin mục tiêu trong trang nắm tay (Chung) và thêm lib của tôi vào danh sách phụ thuộc

sau đó tất cả hoạt động tốt. Cờ "-ObjC" là đủ trong trường hợp của tôi.

Tôi cũng quan tâm đến ý tưởng từ http://iphencedevelopmentexperatics.blogspot.com/2010/03/c chuyên-in-static-l Library.html blog. Tác giả nói rằng anh ta có thể sử dụng danh mục từ lib mà không cần đặt cờ -all_load hoặc -ObjC. Anh ta chỉ cần thêm vào thể loại h / m các tập tin giao diện / triển khai lớp giả để buộc trình liên kết sử dụng tệp này. Và vâng, thủ thuật này làm công việc.

Nhưng tác giả cũng cho biết ông thậm chí không ngay lập tức đối tượng giả. Như tôi đã tìm thấy, chúng ta nên gọi một cách rõ ràng một số mã "thực" từ tệp danh mục. Vì vậy, ít nhất chức năng lớp nên được gọi. Và chúng tôi thậm chí không cần lớp giả. Hàm c đơn làm tương tự.

Vì vậy, nếu chúng ta viết các tập tin lib như:

// mylib.h
void useMyLib();

@interface NSObject (Logger)
-(void)logSelf;
@end


// mylib.m
void useMyLib(){
    NSLog(@"do nothing, just for make mylib linked");
}


@implementation NSObject (Logger)
-(void)logSelf{
    NSLog(@"self is:%@", [self description]);
}
@end

và nếu chúng ta gọi useMyLib (); bất cứ nơi nào trong dự án ứng dụng thì trong bất kỳ lớp nào chúng ta đều có thể sử dụng phương thức thể loại logSelf;

[self logSelf];

Và nhiều blog về chủ đề:

http://t-machine.org/index.php/2009/10/13/how-to-make-an-iphone-static-l Library-part-1 /

http://blog.costan.us/2009/12/fat-iphone-static-lologists-device-and.html


8
Ghi chú công nghệ của Apple dường như đã được sửa đổi để nói rằng "Để giải quyết vấn đề này, liên kết đích với thư viện tĩnh phải chuyển tùy chọn -ObjC cho trình liên kết." đó là điều ngược lại với những gì được trích dẫn ở trên. Chúng tôi chỉ xác nhận rằng bạn phải bao gồm khi liên kết ứng dụng chứ không phải thư viện.
Ken Aspeslagh

Theo doc developer.apple.com/l Library / mac / # qa / qa1490 / _index.html, chúng ta nên sử dụng cờ -all_load hoặc -force_load. Như đã đề cập, trình liên kết không có lỗi trong Ứng dụng Mac và Ứng dụng iPhone 64 bit. "Quan trọng: Đối với các ứng dụng HĐH 64 bit và iPhone, có một lỗi liên kết ngăn -ObjC tải các tệp đối tượng từ các thư viện tĩnh chỉ chứa các danh mục và không có lớp. Cách khắc phục là sử dụng cờ -all_load hoặc -force_load."
Robin

2
@Ken Aspelagh: Cảm ơn, tôi có vấn đề tương tự. Các cờ -ObjC và -all_load cần được thêm vào chính ứng dụng chứ không phải thư viện.
titandecoy

3
Câu trả lời tuyệt vời, mặc dù những người mới đến câu hỏi này nên lưu ý rằng nó đã hết hạn. Kiểm tra stackoverflow câu trả lời của tonklon.com/a/9224606/322748 (all_load / force_load không còn cần thiết)
Jay Peyer

Tôi đã bị mắc kẹt trong những điều này trong gần nửa giờ và với một thử nghiệm và lỗi tôi đã làm cho nó ra. Dù sao cũng cảm ơn. Câu trả lời này có giá trị +1 và bạn đã nhận được điều đó !!!
Deepukjaya

118

Câu trả lời từ Vladimir thực sự khá tốt, tuy nhiên, tôi muốn cung cấp thêm một số kiến ​​thức nền tảng ở đây. Có thể một ngày nào đó ai đó tìm thấy câu trả lời của tôi và có thể thấy nó hữu ích.

Trình biên dịch biến đổi các tệp nguồn (.c, .cc, .cpp, .m) thành các tệp đối tượng (.o). Có một tệp đối tượng cho mỗi tệp nguồn. Các tệp đối tượng chứa các ký hiệu, mã và dữ liệu. Các tệp đối tượng không thể sử dụng trực tiếp bởi hệ điều hành.

Bây giờ khi xây dựng thư viện động (.dylib), khung, gói có thể tải (.bundle) hoặc tệp nhị phân có thể thực thi, các tệp đối tượng này được liên kết với nhau để tạo ra thứ gì đó mà hệ điều hành coi là "có thể sử dụng được", ví dụ như thứ gì đó có thể tải trực tiếp đến một địa chỉ bộ nhớ cụ thể.

Tuy nhiên, khi xây dựng một thư viện tĩnh, tất cả các tệp đối tượng này chỉ được thêm vào một tệp lưu trữ lớn, do đó mở rộng các thư viện tĩnh (.a để lưu trữ). Vì vậy, một tệp .a không gì khác hơn là một tệp lưu trữ các tệp đối tượng (.o). Hãy nghĩ về một kho lưu trữ TAR hoặc một kho lưu trữ ZIP mà không nén. Việc sao chép một tệp .a xung quanh dễ dàng hơn so với toàn bộ các tệp .o (tương tự như Java, nơi bạn đóng gói các tệp. Class vào kho lưu trữ .jar để phân phối dễ dàng).

Khi liên kết nhị phân với thư viện tĩnh (= archive), trình liên kết sẽ nhận được một bảng gồm tất cả các ký hiệu trong kho lưu trữ và kiểm tra xem các ký hiệu nào trong số các ký hiệu này được tham chiếu bởi các nhị phân. Chỉ các tệp đối tượng chứa các ký hiệu được tham chiếu thực sự được tải bởi trình liên kết và được xem xét bởi quá trình liên kết. Ví dụ: nếu kho lưu trữ của bạn có 50 tệp đối tượng, nhưng chỉ có 20 biểu tượng được sử dụng bởi nhị phân, chỉ 20 tệp đó được tải bởi trình liên kết, 30 tệp còn lại hoàn toàn bị bỏ qua trong quá trình liên kết.

Điều này hoạt động khá tốt đối với mã C và C ++, vì các ngôn ngữ này cố gắng làm nhiều nhất có thể vào thời gian biên dịch (mặc dù C ++ cũng có một số tính năng chỉ dành cho thời gian chạy). Obj-C, tuy nhiên, là một loại ngôn ngữ khác. Obj-C phụ thuộc rất nhiều vào các tính năng thời gian chạy và nhiều tính năng Obj-C thực sự là các tính năng chỉ chạy. Các lớp Obj-C thực sự có các ký hiệu có thể so sánh với các hàm C hoặc các biến C toàn cầu (ít nhất là trong thời gian chạy Obj-C hiện tại). Một trình liên kết có thể xem một lớp có được tham chiếu hay không, vì vậy nó có thể xác định một lớp đang được sử dụng hay không. Nếu bạn sử dụng một lớp từ một tệp đối tượng trong một thư viện tĩnh, tệp đối tượng này sẽ được trình liên kết tải lên vì trình liên kết nhìn thấy một biểu tượng đang được sử dụng. Danh mục là một tính năng chỉ dành cho thời gian chạy, các danh mục không phải là biểu tượng như các lớp hoặc hàm và điều đó cũng có nghĩa là một trình liên kết không thể xác định xem một danh mục có được sử dụng hay không.

Nếu trình liên kết tải một tệp đối tượng chứa mã Obj-C, tất cả các phần Obj-C của nó luôn là một phần của giai đoạn liên kết. Vì vậy, nếu một tệp đối tượng chứa các danh mục được tải vì bất kỳ ký hiệu nào từ nó được coi là "đang sử dụng" (có thể là một lớp, có thể là một biến toàn cục), các thể loại cũng được tải và sẽ có sẵn trong thời gian chạy . Tuy nhiên, nếu tệp đối tượng tự nó không được tải, các thể loại trong đó sẽ không có sẵn trong thời gian chạy. Một đối tượng tập tin có chứa chỉ loại được không bao giờ được nạp bởi vì nó có chứa không có biểu tượng các mối liên kết sẽ không bao giờ xem xét "sử dụng". Và đây là toàn bộ vấn đề ở đây.

Một số giải pháp đã được đề xuất và bây giờ bạn biết làm thế nào tất cả những điều này kết hợp với nhau, chúng ta hãy có cái nhìn khác về giải pháp được đề xuất:

  1. Một giải pháp là thêm -all_loadvào cuộc gọi liên kết. Cờ liên kết đó thực sự sẽ làm gì? Trên thực tế, nó nói với trình liên kết " Tải tất cả các tệp đối tượng của tất cả các tài liệu lưu trữ bất kể bạn có thấy bất kỳ biểu tượng nào được sử dụng hay không ". Tất nhiên, điều đó sẽ hoạt động; nhưng nó cũng có thể tạo ra các nhị phân khá lớn.

  2. Một giải pháp khác là thêm -force_loadvào lệnh gọi liên kết bao gồm đường dẫn đến kho lưu trữ. Cờ này hoạt động chính xác như thế -all_load, nhưng chỉ cho kho lưu trữ được chỉ định. Tất nhiên điều này sẽ làm việc như là tốt.

  3. Giải pháp phổ biến nhất là thêm -ObjCvào cuộc gọi liên kết. Cờ liên kết đó thực sự sẽ làm gì? Cờ này cho trình liên kết " Tải tất cả các tệp đối tượng từ tất cả các tài liệu lưu trữ nếu bạn thấy rằng chúng có chứa bất kỳ mã Obj-C nào ". Và "bất kỳ mã Obj-C" bao gồm các danh mục. Điều này cũng sẽ hoạt động và nó sẽ không buộc tải các tệp đối tượng không chứa mã Obj-C (những tệp này vẫn chỉ được tải theo yêu cầu).

  4. Một giải pháp khác là cài đặt xây dựng Xcode khá mới Perform Single-Object Prelink. Cài đặt này sẽ làm gì? Nếu được bật, tất cả các tệp đối tượng (hãy nhớ, có một tệp cho mỗi tệp nguồn) được hợp nhất với nhau thành một tệp đối tượng (đó không phải là liên kết thực, do đó tên PreLink ) và tệp đối tượng duy nhất này (đôi khi còn được gọi là "đối tượng chính tập tin ") sau đó được thêm vào kho lưu trữ. Nếu bây giờ bất kỳ ký hiệu nào của tệp đối tượng chính được xem xét sử dụng, toàn bộ tệp đối tượng chính sẽ được xem xét sử dụng và do đó tất cả các phần Objective-C của nó luôn được tải. Và vì các lớp là các ký hiệu bình thường, nên đủ để sử dụng một lớp từ thư viện tĩnh như vậy để có được tất cả các danh mục.

  5. Giải pháp cuối cùng là mẹo mà Vladimir thêm vào cuối câu trả lời của mình. Đặt một " biểu tượng giả " vào bất kỳ tệp nguồn nào chỉ khai báo các danh mục. Nếu bạn muốn sử dụng bất kỳ danh mục nào trong thời gian chạy, hãy đảm bảo rằng bằng cách nào đó bạn tham chiếu biểu tượng giả một khi đã đọc hoặc đã viết, điều này là đủ). Không giống như tất cả các giải pháp khác ở trên, giải pháp này chuyển điều khiển về các danh mục có sẵn trong thời gian chạy sang mã được biên dịch (nếu nó muốn được liên kết và có sẵn, nó truy cập biểu tượng, nếu không nó không truy cập vào biểu tượng và trình liên kết sẽ bỏ qua nó). khi biên dịch, vì điều này làm cho tệp đối tượng được tải bởi trình liên kết và do đó cũng có tất cả mã Obj-C trong đó. Ví dụ, nó có thể là một hàm có thân hàm rỗng (sẽ không làm gì khi được gọi) hoặc nó có thể là biến toàn cục được truy cập (ví dụ: toàn cụcint

Đó là tất cả mọi người.

Oh, đợi đã, còn một điều nữa:
Trình liên kết có một tùy chọn được đặt tên -dead_strip. Tùy chọn này làm gì? Nếu trình liên kết quyết định tải một tệp đối tượng, tất cả các ký hiệu của tệp đối tượng trở thành một phần của nhị phân được liên kết, cho dù chúng có được sử dụng hay không. Ví dụ: một tệp đối tượng chứa 100 hàm, nhưng chỉ một trong số chúng được sử dụng bởi nhị phân, tất cả 100 hàm vẫn được thêm vào nhị phân vì các tệp đối tượng được thêm vào hoặc toàn bộ chúng không được thêm vào. Thêm một phần đối tượng thường không được hỗ trợ bởi các trình liên kết.

Tuy nhiên, nếu bạn nói với trình liên kết là "dải chết", trước tiên trình liên kết sẽ thêm tất cả các tệp đối tượng vào tệp nhị phân, giải quyết tất cả các tham chiếu và cuối cùng quét nhị phân cho các ký hiệu không được sử dụng (hoặc chỉ được sử dụng bởi các ký hiệu khác không có trong sử dụng). Tất cả các biểu tượng được tìm thấy không được sử dụng sau đó được xóa như một phần của giai đoạn tối ưu hóa. Trong ví dụ trên, 99 hàm không sử dụng được loại bỏ một lần nữa. Điều này rất hữu ích nếu bạn sử dụng các tùy chọn như -load_all, -force_loadhoặc Perform Single-Object Prelinkbởi vì các tùy chọn này có thể dễ dàng làm tăng đáng kể kích thước nhị phân trong một số trường hợp và tước chết sẽ xóa lại mã và dữ liệu không sử dụng.

Tước chết hoạt động rất tốt cho mã C (ví dụ: các hàm không sử dụng, các biến và hằng được loại bỏ như mong đợi) và nó cũng hoạt động khá tốt cho C ++ (ví dụ: các lớp không sử dụng được loại bỏ). Nó không hoàn hảo, trong một số trường hợp, một số biểu tượng không bị xóa mặc dù có thể xóa chúng đi, nhưng trong hầu hết các trường hợp, nó hoạt động khá tốt đối với các ngôn ngữ này.

Còn Obj-C thì sao? Quên nó đi! Không có tước chết cho Obj-C. Vì Obj-C là ngôn ngữ tính năng thời gian chạy, trình biên dịch không thể nói tại thời điểm biên dịch cho dù một biểu tượng có thực sự được sử dụng hay không. Ví dụ, một lớp Obj-C không được sử dụng nếu không có mã trực tiếp tham chiếu đến nó, đúng không? Sai lầm! Bạn có thể tự động xây dựng một chuỗi chứa một tên lớp, yêu cầu một con trỏ lớp cho tên đó và tự động phân bổ lớp. Ví dụ thay vì

MyCoolClass * mcc = [[MyCoolClass alloc] init];

Tôi cũng có thể viết

NSString * cname = @"CoolClass";
NSString * cnameFull = [NSString stringWithFormat:@"My%@", cname];
Class mmcClass = NSClassFromString(cnameFull);
id mmc = [[mmcClass alloc] init];

Trong cả hai trường hợp mmclà một tham chiếu đến một đối tượng của lớp "MyCoolClass", nhưng không có tham chiếu trực tiếp đến lớp này trong mẫu mã thứ hai (thậm chí không phải tên lớp là một chuỗi tĩnh). Mọi thứ chỉ xảy ra trong thời gian chạy. Và đó là mặc dù các lớp học thực sự những biểu tượng thực sự. Nó thậm chí còn tồi tệ hơn cho các thể loại, vì chúng thậm chí không phải là biểu tượng thực sự.

Vì vậy, nếu bạn có một thư viện tĩnh với hàng trăm đối tượng, nhưng hầu hết các nhị phân của bạn chỉ cần một vài trong số chúng, bạn có thể không muốn sử dụng các giải pháp (1) đến (4) ở trên. Nếu không, bạn kết thúc với các nhị phân rất lớn chứa tất cả các lớp này, mặc dù hầu hết chúng không bao giờ được sử dụng. Đối với các lớp bạn thường không cần bất kỳ giải pháp đặc biệt nào vì các lớp có ký hiệu thực và miễn là bạn tham chiếu chúng trực tiếp (không phải trong mẫu mã thứ hai), trình liên kết sẽ tự xác định cách sử dụng của chúng khá tốt. Tuy nhiên, đối với các danh mục, hãy xem xét giải pháp (5), vì nó chỉ có thể bao gồm các danh mục bạn thực sự cần.

Ví dụ: nếu bạn muốn một danh mục cho NSData, ví dụ: thêm phương thức nén / giải nén vào nó, bạn sẽ tạo một tệp tiêu đề:

// NSData+Compress.h
@interface NSData (Compression)
    - (NSData *)compressedData;
    - (NSData *)decompressedData;
@end

void import_NSData_Compression ( );

và một tập tin thực hiện

// NSData+Compress
@implementation NSData (Compression)
    - (NSData *)compressedData 
    {
        // ... magic ...
    }

    - (NSData *)decompressedData
    {
        // ... magic ...
    }
@end

void import_NSData_Compression ( ) { }

Bây giờ chỉ cần đảm bảo rằng bất cứ nơi nào trong mã của bạn import_NSData_Compression()được gọi. Không quan trọng nó được gọi ở đâu hoặc tần suất được gọi như thế nào. Trên thực tế, nó thực sự không cần phải được gọi, nó là đủ nếu trình liên kết nghĩ như vậy. Ví dụ: bạn có thể đặt đoạn mã sau ở bất cứ đâu trong dự án của bạn:

__attribute__((used)) static void importCategories ()
{
    import_NSData_Compression();
    // add more import calls here
}

Bạn không cần phải gọi importCategories()mã của mình, thuộc tính sẽ làm cho trình biên dịch và trình liên kết tin rằng nó được gọi, ngay cả trong trường hợp không.

Và một mẹo cuối cùng:
Nếu bạn thêm -whyloadvào lệnh gọi liên kết cuối cùng, trình liên kết sẽ in trong nhật ký xây dựng tệp đối tượng mà thư viện đã tải từ đó vì sử dụng ký hiệu nào. Nó sẽ chỉ in biểu tượng đầu tiên được xem xét sử dụng, nhưng đó không nhất thiết là biểu tượng duy nhất được sử dụng của tệp đối tượng đó.


1
Cảm ơn bạn đã đề cập -whyload, cố gắng gỡ lỗi tại sao trình liên kết đang làm một cái gì đó có thể khá khó khăn!
Ben S

Có một tùy chọn Dead Code Strippingtrong Build Settings>Linking. Có giống như -dead_stripđược thêm vào Other Linker Flags?
Xiao

1
@Sean Vâng, nó giống nhau. Chỉ cần đọc "Trợ giúp nhanh" tồn tại cho mọi cài đặt bản dựng, câu trả lời là có ngay: postimg.org/image/n7megftnr/full
Mecki

@Mecki Cảm ơn. Tôi đã cố gắng để thoát khỏi -ObjC, vì vậy tôi đã thử hack của bạn nhưng nó phàn nàn "import_NSString_jsonObject()", referenced from: importCategories() in main.o ld: symbol(s) not found. Tôi đặt import_NSString_jsonObjecttrong khung nhúng tôi đặt tên Utility, và thêm #import <Utility/Utility.h>với __attribute__tuyên bố vào cuối của tôi AppDelegate.h.
Xiao

@Sean Nếu trình liên kết không thể tìm thấy biểu tượng, bạn không liên kết với thư viện tĩnh có chứa biểu tượng. Chỉ cần nhập tệp ah từ khung sẽ không tạo liên kết Xcode với khung. Khung phải được liên kết rõ ràng trong liên kết với giai đoạn xây dựng khung. Bạn có thể muốn mở ra một câu hỏi riêng cho vấn đề liên kết của mình, trả lời trong các bình luận rất cồng kềnh và bạn cũng không thể cung cấp thông tin như đầu ra nhật ký xây dựng.
Mecki

24

Vấn đề này đã được sửa trong LLVM . Bản sửa lỗi vận chuyển như một phần của LLVM 2.9 Phiên bản Xcode đầu tiên có chứa bản sửa lỗi là Xcode 4.2 vận chuyển với LLVM 3.0. Việc sử dụng -all_loadhoặc -force_loadkhông còn cần thiết khi làm việc với XCode 4.2 -ObjC vẫn cần thiết.


Bạn có chắc về điều này? Tôi đang làm việc trên một dự án iOS bằng Xcode 4.3.2, biên dịch với LLVM 3.1 và đây vẫn là một vấn đề đối với tôi.
Ashley Mills

Ok, đó là một chút thiếu chính xác. Các -ObjClá cờ vẫn còn cần thiết và sẽ luôn như vậy. Cách giải quyết là việc sử dụng -all_loadhoặc -force_load. Và điều đó không còn cần thiết nữa. Tôi đã sửa câu trả lời của tôi ở trên.
tonklon

Có bất kỳ nhược điểm nào trong việc bao gồm cờ -all_load (ngay cả khi không cần thiết) không? Nó có ảnh hưởng đến thời gian biên dịch / khởi chạy theo bất kỳ cách nào không?
ZS

Tôi đang làm việc với Xcode Phiên bản 4.5 (4G182) và cờ -ObjC di chuyển lỗi bộ chọn không được nhận dạng của tôi từ sự phụ thuộc của bên thứ 3 Tôi đang cố gắng sử dụng vào độ sâu của thời gian chạy Objective C: "- [__ NSArrayM map :]: bộ chọn không được nhận dạng được gửi đến ví dụ ... ". Bất kì manh mối nào?
Robert Atkins

16

Đây là những gì bạn cần làm để giải quyết hoàn toàn vấn đề này khi biên dịch thư viện tĩnh của bạn:

Đi đến Cài đặt bản dựng Xcode và đặt Thực hiện Mở đầu đối tượng đơn thành CÓ hoặc GENERATE_MASTER_OBJECT_FILE = YEStrong tệp cấu hình bản dựng của bạn.

Theo mặc định, trình liên kết tạo tệp .o cho mỗi tệp .m. Vì vậy, các loại được tập tin .o khác nhau. Khi trình liên kết xem xét một tệp .o thư viện tĩnh, nó không tạo ra một chỉ mục của tất cả các biểu tượng cho mỗi lớp (Thời gian chạy sẽ không thành vấn đề).

Lệnh này sẽ yêu cầu trình liên kết đóng gói tất cả các đối tượng lại thành một tệp .o lớn và bằng cách này, nó buộc trình liên kết xử lý thư viện tĩnh để lấy chỉ mục tất cả các loại lớp.

Hy vọng rằng làm rõ nó.


Điều này đã sửa nó cho tôi mà không cần phải thêm -ObjC vào mục tiêu liên kết.
Matthew Crenshaw

Sau khi cập nhật lên phiên bản mới nhất của thư viện BlocksKit , tôi đã phải sử dụng cài đặt này để khắc phục sự cố (Tôi đã sử dụng cờ -ObjC nhưng vẫn thấy sự cố).
rakmoh

1
Thật ra câu trả lời của bạn không hoàn toàn đúng. Tôi không "yêu cầu trình liên kết đóng gói tất cả các danh mục của cùng một lớp vào một tệp .o", nó yêu cầu trình liên kết liên kết tất cả các tệp đối tượng (.o) thành một tệp đối tượng lớn trước khi tạo một thư viện tĩnh chung no. Khi bất kỳ biểu tượng nào được tham chiếu từ thư viện, tất cả các biểu tượng được tải. Tuy nhiên, điều này sẽ không hoạt động nếu không có biểu tượng nào được tham chiếu (ví dụ: nếu nó không hoạt động nếu chỉ có các danh mục trong thư viện).
Mecki

Tôi không nghĩ rằng điều này sẽ hoạt động nếu bạn thêm các danh mục vào các lớp hiện có, chẳng hạn như NSData.
Bob Whiteman

Tôi cũng gặp khó khăn khi thêm các thể loại vào các lớp hiện có. Plugin của tôi không thể nhận ra chúng trong thời gian chạy.
David Dunham

9

Một yếu tố hiếm khi được đề cập mỗi khi thảo luận liên kết thư viện tĩnh xuất hiện là thực tế là bạn cũng phải bao gồm chính các danh mục trong các giai đoạn xây dựng-> sao chép tệp và biên dịch nguồn của chính thư viện tĩnh .

Apple cũng không nhấn mạnh thực tế này trong Sử dụng Thư viện tĩnh được xuất bản gần đây của họ .

Tôi đã dành cả ngày để thử tất cả các loại biến thể của -objC và -all_load, v.v. nhưng không có gì phát sinh từ nó .. điều này câu hỏi khiến tôi chú ý vấn đề đó. (đừng hiểu sai ý tôi .. bạn vẫn phải làm công cụ -objC .. nhưng nó còn hơn thế nữa).

Ngoài ra, một hành động khác luôn giúp tôi là tôi luôn tự mình xây dựng thư viện tĩnh bao gồm .. sau đó tôi xây dựng ứng dụng kèm theo ..


-1

Bạn có thể cần phải có danh mục trong tiêu đề "công khai" của thư viện tĩnh: #import "MyStaticLib.h"

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.