เมื่อใดที่เราควรใช้“ ไบนารีที่ฝังตัว” มากกว่า“ Linked Frameworks” ใน Xcode


140

มีคำถามที่ดีเกี่ยวกับความแตกต่างระหว่างทั้งสองตัวเลือกที่อธิบายไว้ในคือการเชื่อมโยงกับห้องสมุดไบนารี VS กรอบฝัง

ดูเหมือนว่าเรามีตัวเลือกในการใช้ทั้งคู่สงสัยว่ากรณีใดที่เราควรใช้ไบนารีแบบฝังที่ดีกว่าหรือแทนที่จะเป็นเฟรมเวิร์กที่เชื่อมโยง

มีตัวอย่างที่ชัดเจนใด ๆ ในการจัดการเรื่องนี้ให้ชัดเจนยิ่งขึ้น? ขอบคุณ


คำตอบ:


239

คำถามที่คุณเชื่อมโยงอ้างอิงถึงฟังก์ชั่น "เชื่อมโยงไบนารีกับห้องสมุด" ซึ่งค่อนข้างแตกต่างจากไบนารีฝังตัว

"ลิงก์ไบนารีกับไลบรารี" หมายถึงสิ่งที่คุณคาดหวังว่าจะเกี่ยวกับการเชื่อมโยง: ไม่ว่าไบนารีนั้นจะเป็นไลบรารีแบบคงที่ไลบรารีแบบไดนามิกหรือกรอบจะถูกเชื่อมโยงกับรหัสวัตถุของคุณในเวลาเชื่อมโยงหลังจากรวบรวม

เมื่อคุณคิดถึงการเชื่อมโยงกับไลบรารีแบบคงที่สิ่งที่เกิดขึ้นค่อนข้างชัดเจน: ตัวเชื่อมโยงคัดลอกรหัสจากไลบรารี (เช่นlibFoo.a ) ลงในไบนารีเอาต์พุตของคุณ ไฟล์เอาต์พุตของคุณมีขนาดโตขึ้น แต่ไม่จำเป็นต้องแก้ไขการขึ้นต่อกันภายนอกของรันไทม์ ทุกสิ่งที่โปรแกรมของคุณจำเป็นต้องเรียกใช้ (สำหรับไลบรารีแบบสแตติก) จะปรากฏหลังจากสร้างขึ้นแล้ว

ด้วยไลบรารีไดนามิก (.dylib หรือเฟรมเวิร์กที่ระบบจัดหา) ความคาดหวังก็คือไลบรารีที่คุณกำลังลิงก์จะปรากฏที่ใดที่หนึ่งในพา ธ โหลดไลบรารีไดนามิกของระบบเมื่อคุณรันโปรแกรม วิธีนี้คุณจะไม่มีค่าใช้จ่ายในการคัดลอกไลบรารี่ภายนอกของบุคคลภายนอกทั้งหมดลงในไบนารี่ของคุณและโปรแกรมต่าง ๆ ทั้งหมดบนคอมพิวเตอร์ที่เชื่อมโยงไปยังไลบรารี่นั้นจะสามารถค้นหาได้ซึ่งจะช่วยประหยัดพื้นที่ดิสก์น้อยที่สุด พื้นที่หน่วยความจำอาจขึ้นอยู่กับวิธีและตำแหน่งของระบบแคชไลบรารี

เฟรมเวิร์กคล้ายกับไลบรารีแบบไดนามิก แต่สามารถมีทรัพยากรในโครงสร้างไดเรกทอรี (รูปภาพเสียงกรอบงานอื่น ๆ ) ในกรณีนี้คงห้องสมุดหรือ .dylib ไฟล์ง่ายจะไม่ตัดมันดังนั้นคุณอาจจะต้องเชื่อมโยงไปยังกรอบเพียงเพื่อให้มันสามารถค้นหาสิ่งที่จะต้องมีการทำงานอย่างถูกต้อง

เมื่อคุณลิงก์ไปยังเฟรมเวิร์กของบุคคลที่สาม (พูดบางสิ่งที่คุณดาวน์โหลดจาก GitHub และสร้างขึ้นเอง) อาจไม่ปรากฏบนระบบที่คุณตั้งใจจะใช้งาน ในกรณีนี้คุณจะไม่เพียง แต่ลิงก์ไปยังเฟรมเวิร์ก แต่ฝังไว้ในชุดแอปพลิเคชันของคุณและใช้เฟส "คัดลอกเฟรมเวิร์ก" เมื่อโปรแกรมของคุณรัน runtime-linker (aka ตัวแก้ไข) จะมองเข้าไปในชุดข้อมูลเพิ่มเติมนอกเหนือจากพา ธ ของตัวโหลดระบบค้นหาเฟรมเวิร์กที่ฝังตัวและลิงก์เพื่อให้แอปของคุณมีรหัสที่ต้องการเพื่อทำงาน

ในที่สุดสิ่งที่ถูกต้อง "ฝังตัวไบนารี" เป็นปฏิบัติการที่คุณทั้งสองฝังในชุดใบสมัครของคุณผ่านขั้นตอนการคัดลอกไฟล์และที่คุณดำเนินการด้วยตัวคุณเองอาจมีการโทรpopen()หรือคล้ายกัน โปรแกรมของคุณอาจถูกฝังไว้ไบนารี แต่มันไม่ได้เชื่อมโยงกับมัน มันเป็นเอนทิตี้ภายนอกอย่างสมบูรณ์ (เช่นโปรแกรมใน/binไดเรกทอรี)

ในทางปฏิบัติสำหรับไลบรารีและเฟรมเวิร์กที่ระบบจัดเตรียมไว้คุณจะเชื่อมโยงกับพวกเขาและนั่นคือทั้งหมดที่คุณต้องทำ

หากคุณต้องการเชื่อมโยงไลบรารีที่คุณสร้างขึ้นซึ่งไม่ต้องการทรัพยากรใด ๆ ในตัว (เช่นไม่ต้องการเฟรมเวิร์ก) คุณก็สามารถลิงก์กับไลบรารีแบบคงที่ได้ หากคุณพบว่าคุณมีโมดูลหลายโมดูลในโปรแกรมของคุณที่ต้องการใช้รหัสไลบรารีเดียวกันจากนั้นแปลงเป็นเฟรมเวิร์กหรือไลบรารีแบบไดนามิกและเชื่อมโยงกับที่สามารถประหยัดพื้นที่และอาจจะสะดวก (โดยเฉพาะอย่างยิ่งถ้าใช้หน่วยความจำเป็นกังวล)

ในที่สุดเฟรมเวิร์กอาจรวมถึงทรัพยากรไม่เพียง แต่ส่วนหัวและ / หรือไฟล์ลิขสิทธิ์ การใช้เฟรมเวิร์กในการถ่ายทอดไฟล์เหล่านี้เป็นกลไกการกระจายที่สะดวกดังนั้นบ่อยครั้งที่คุณอาจต้องการรวมเฟรมเวิร์กเพื่อให้สิ่งเหล่านี้สามารถติดแท็กพร้อมกับไบนารีของคุณ (เช่นข้อกำหนดสิทธิ์ใช้งานอาจทำให้ข้อบังคับนี้บังคับ)

--- แก้ไข ---

Adam Johns โพสต์คำถามต่อไปนี้เป็นความคิดเห็น:

นี่คือคำตอบที่ดี มีบางอย่างที่ฉันยังสับสนอยู่เล็กน้อย การรันไบนารีด้วยตัวคุณเองหมายความว่าอย่างไร? คุณหมายถึงเพียงแค่ใช้รหัสของเฟรมเวิร์กในตัว ฉันรู้ว่าคุณพูดถึง popen () แต่คุณกำลังบอกว่าแอพของฉันกำลังโทรหา popen ()? ฉันไม่รู้จริงๆว่ามันหมายถึงอะไร

ฉันกำลังบอกว่าไบนารีฝังตัวเป็นเพียงไฟล์ทรัพยากรอื่นในบันเดิลของคุณเช่นไฟล์เสียงหรือรูปภาพแม้ว่าไฟล์นั้นจะเป็นเครื่องมือบรรทัดคำสั่งที่ใช้แทนได้ popen()ฟังก์ชั่น ( man popenจากสถานีของคุณเพื่ออ่านข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้) ช่วยให้คุณสามารถรันโปรแกรมโดยพลการทำงานจากโปรแกรมอื่น system()ฟังก์ชั่นเป็นวิธีอื่น มีคนอื่นและฉันจะให้ตัวอย่างประวัติศาสตร์ที่นี่ที่อาจทำให้เข้าใจการใช้ไบนารีฝังตัวที่ชัดเจนยิ่งขึ้น:

อย่างที่คุณอาจทราบเมื่อคุณเปิดแอพใน Mac OS X มันจะเปิดตัวพร้อมกับรหัสผู้ใช้ของผู้ใช้ปัจจุบัน ภายใต้การติดตั้งที่พบมากที่สุดที่เริ่มต้นใช้ at-the-สก์ท็อปของผู้ใช้ที่จะได้รับรหัสผู้ใช้admin501

บนระบบปฏิบัติการที่ใช้ Unix เฉพาะrootผู้ใช้ (ID ผู้ใช้0) เท่านั้นที่สามารถเข้าถึงระบบไฟล์ทั้งหมดได้อย่างสมบูรณ์ บางครั้งมันเกิดขึ้นที่โปรแกรมติดตั้งที่ผู้ใช้เดสก์ท็อปเปิดตัวจำเป็นต้องติดตั้งไฟล์ในไดเรกทอรีที่มีสิทธิพิเศษ (ตัวอย่างเช่นไดรเวอร์) ในกรณีนี้แอ็พพลิเคชันโปรแกรมจำเป็นต้องเพิ่มสิทธิ์ให้แก่rootผู้ใช้เพื่อให้สามารถเขียนในไดเร็กทอรีที่ จำกัด เหล่านี้

เพื่ออำนวยความสะดวกในระบบปฏิบัติการผ่าน OS X 10.7, Apple ได้จัดเตรียมฟังก์ชันการอนุญาต AuthorizationExecuteWithPrivileges ()ไว้ในAPIการอนุญาตบริการ API () (ตอนนี้เลิกใช้แล้ว แต่ยังเป็นตัวอย่างที่มีประโยชน์)

AuthorizationExecuteWithPrivileges()rootเอาเป็นอาร์กิวเมนต์เส้นทางไปยังเครื่องมือบรรทัดคำสั่งที่จะดำเนินการเป็น เครื่องมือบรรทัดคำสั่งคือเชลล์สคริปต์ที่รันได้หรือไบนารีที่คอมไพล์ซึ่งคุณเขียนเพื่อรันตรรกะการติดตั้งของคุณ เครื่องมือนี้ถูกติดตั้งภายในชุดแอปพลิเคชันของคุณเช่นเดียวกับไฟล์ทรัพยากรอื่น ๆ

เมื่อมีการเรียกใช้ระบบปฏิบัติการจะสร้างกล่องโต้ตอบอนุญาตให้ขอรหัสผ่านของผู้ใช้ (คุณเคยเห็นมาก่อน!) และเมื่อป้อนแล้วจะเรียกใช้งานโปรแกรมrootในนามของแอปของคุณ กระบวนการนี้คล้ายกับเพียงแค่เรียกใช้โปรแกรมด้วยpopen()ตัวเอง แต่popen()เพียงอย่างเดียวไม่ได้ให้ประโยชน์ในการเพิ่มระดับสิทธิ์ให้คุณ


62
คุณจะรู้สิ่งเหล่านี้ได้อย่างไร
Ian Warburton

56
@IanWarburton ฉันเขียนโปรแกรมระบบปฏิบัติการ Apple มานานกว่า 20 ปีแล้วและหยิบของขึ้นมาสองสามอัน :)
ตรา

1
@ จัสตินมาร์ตินฉันหมายถึงlinkแต่คุณถูกต้องที่คุณต้องฝังไว้ในเฟสการคัดลอกไฟล์ (มิฉะนั้นคุณจะใช้มันอย่างไร) เป้าหมายของการใช้เฟรมเวิร์กของบุคคลที่สามหรือไบนารีแบบฝังคือการเรียกใช้โค้ดที่เอนทิตีจัดให้ ด้วยไบนารีฝังตัวไม่มีการเชื่อมโยงที่เกี่ยวข้อง ที่รันไทม์คุณสร้างเส้นทางไปยังไบนารีจากนั้นดำเนินการด้วยตนเอง ด้วยเฟรมเวิร์กตัวรวบรวมเวลารวบรวมลิงก์จะเชื่อมโยงเมื่อคุณสร้างแอปของคุณจากนั้น (ถ้าเป็นกรอบงานของบุคคลที่สาม) คุณฝังผ่านเฟสคัดลอกไฟล์และสุดท้ายลิงค์ลิงเกอร์ก็เชื่อมโยงอีกครั้งเมื่อคุณเรียกใช้แอป .
พาร์

1
สิ่งต่าง ๆ ไม่ชัดเจนสำหรับสิ่งที่คุณตอบ @JustAMartin เป้าหมายของการใช้เฟรมเวิร์กของบุคคลที่สามหรือไบนารีแบบฝังคือการเรียกใช้โค้ดที่เอนทิตีจัดให้ ทุกวันนี้ระบบฝังตัวแบบไบนารี่สามารถเป็นเฟรมเวิร์กของบุคคลที่สาม ฉันกำลังพยายามที่จะเข้าใจสิ่งที่คุณหมายถึงที่นี่ ... AFA ฉันเข้าใจไบนารีฝังตัวหมายถึงไบนารีแยกต่างหากของกรอบที่ฝังตัวจะถูกนำเข้าสู่กลุ่มแอพและถ้าคุณเพียงเชื่อมโยงกรอบเดียวกันมันจะทำให้มันเป็นไบนารีเดียวกัน ของแอป โปรดแก้ไขฉันถ้าฉันผิด ...
hariszaman

1
อาจมีเวทมนต์ Xcode ใหม่ที่จะโหลดเฟรมเวิร์กที่ฝังตัว นานแล้วที่ฉันต้องการฟังก์ชั่นนั้น หากคุณต้องการสำรวจว่าเกิดอะไรขึ้นเพิ่มเติมโปรดโพสต์คำถามใหม่ที่นี่ใน SO
ตราไว้หุ้นละ

35

ในระยะสั้น

  • ไลบรารีระบบเชื่อมโยง;
  • ห้องสมุดของบุคคลที่สามฝังพวกเขา

ทำไม?

  • หากคุณพยายามฝังไลบรารี่ของระบบคุณจะไม่พบไลบรารีเหล่านั้นในรายการป๊อปอัพ
  • หากคุณลิงก์ห้องสมุดของบุคคลที่สามคุณอาจจะได้รับความเสียหาย

7

มันเป็นส่วนหนึ่งของDependencyการจัดการ[เกี่ยวกับ]

โปรดทราบว่าXcode 11มีเฉพาะFrameworks, Libraries, and Embedded Contentส่วนในGeneralแท็บ

ลิงค์ไบนารี่

Build Phases -> Link Binary With LibrariesGeneral -> Linked Frameworks and Librariesเป็นกระจกของ

ห้องสมุดคงที่และกรอบ

หากคุณเพิ่ม a Static Library or Static Frameworkในส่วนนี้จะปรากฏที่Frameworks กลุ่ม[เกี่ยวกับ] ( Project Navigator -> <workspace/project> -> Frameworks) และจะมีการอ้างอิงเพิ่มไว้ในโครงการของคุณ Static Linkerจากนั้นก็จะนำมาใช้โดย Static Linkerณ เวลารวบรวมจะรวม / คัดลอกโค้ดทั้งหมดจากไลบรารีไปยังไฟล์อ็อบเจ็กต์ที่รันได้ Static linkerทำงานคู่กับBuild Settings -> <Library/Framework> Search Paths

Static Library

Static Framework

  • Build Settings -> Framework Search Paths. หากคุณไม่เพิ่มstatic frameworkในส่วนนี้คุณจะได้รับข้อผิดพลาดในการคอมไพล์[ไม่มีโมดูลดังกล่าว]

ฝังไบนารี

ห้องสมุดคงและกรอบคงที่

การฝังจะไม่สมเหตุสมผลสำหรับ a Static LibraryและStatic Frameworkเนื่องจากสัญลักษณ์จากพวกมันถูกคอมไพล์ลงในไบนารีที่ปฏิบัติการได้ Xcode จะไม่ปล่อยให้คุณวางstatic libraryไว้ใต้ส่วนการฝัง

Dynamic Framework

Build Phases -> Embed FrameworksGeneral -> Embedded Binariesเป็นกระจกของ การฝังเพิ่มสำเนาของเฟรมเวิร์กลงในบันเดิลของแอปพลิเคชันของคุณ ดังนั้นเมื่อเฟรมเวิร์กถูกเพิ่ม / เอาออกไปยังEmbedส่วนมันจะถูกเพิ่ม / ลบโดยอัตโนมัติไปยังLinkedส่วน ตามค่าเริ่มต้นโฟลเดอร์ของบันเดิลจะเป็นFrameworksแต่คุณสามารถเปลี่ยนได้โดยใช้Destinationฟิลด์ Subpathนอกจากนี้คุณสามารถระบุ

Dynamic linker :dyldที่โหลดหรือรันไทม์จะพยายามค้นหาเฟรมเวิร์กที่ฝังตัวโดยใช้@rpath[เกี่ยวกับ]หากไม่พบข้อผิดพลาดจะเกิดขึ้น[dyld: Library not load]

[เมื่อใช้ลิงก์และฝัง]

[คำศัพท์]

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.