การเชื่อมโยงไลบรารีแบบคงที่กับไลบรารีแบบคงที่อื่น ๆ


142

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

ห้องสมุดคงที่ของฉันเรียกมันว่า X รวบรวมได้ดี

ฉันได้สร้างโปรแกรมตัวอย่างง่ายๆที่ใช้ฟังก์ชันจาก X แต่เมื่อฉันพยายามเชื่อมโยงกับ X ฉันได้รับข้อผิดพลาดมากมายเกี่ยวกับสัญลักษณ์ที่หายไปจากไลบรารี a_1 - a_n

มีวิธีใดบ้างที่ฉันสามารถสร้างไลบรารีแบบคงที่ Y ที่มี X และฟังก์ชันทั้งหมดที่ต้องการโดย X (บิตที่เลือกจาก a_1 - a_n) เพื่อให้ฉันสามารถแจกจ่ายเฉพาะ Y เพื่อให้ผู้คนเชื่อมโยงโปรแกรมของตนได้


อัพเดท:

ฉันดูแค่การทิ้งทุกอย่างด้วยarและสร้าง mega-lib หนึ่งอัน แต่สุดท้ายก็มีสัญลักษณ์มากมายที่ไม่จำเป็น (ไฟล์. o ทั้งหมดมีขนาดประมาณ 700 MB อย่างไรก็ตามไฟล์ปฏิบัติการที่เชื่อมโยงแบบคงที่คือ 7 MB). มีวิธีที่ดีในการรวมเฉพาะสิ่งที่จำเป็นจริงหรือไม่?


สิ่งนี้มีความเกี่ยวข้องอย่างใกล้ชิดกับวิธีการรวมไลบรารี C / C ++ หลายไลบรารีไว้ในที่เดียว? .

คำตอบ:


79

ไลบรารีแบบคงที่ไม่เชื่อมโยงกับไลบรารีแบบคงที่อื่น ๆ วิธีเดียวที่จะทำได้คือใช้เครื่องมือ librarian / archiver ของคุณ (เช่นarบน Linux) เพื่อสร้างสแตติกไลบรารีใหม่เดียวโดยเชื่อมต่อไลบรารีหลาย ๆ ไลบรารี

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


สวัสดีนีลฉันได้อัปเดตคำถาม - คุณรู้วิธีใดในการรวมเฉพาะไฟล์. o ที่จำเป็น?
Jason Sundram

อัปเดต - หากคุณพบว่าตัวเองต้องการทำสิ่งนี้ให้ถอยกลับและทำอย่างอื่น (เว้นแต่ตามที่ John Knoeller ชี้ให้เห็นว่าคุณกำลังใช้ Visual Studio) ฉันจมลงไปในแนวทางนี้เป็นจำนวนมากและไม่ได้รับประโยชน์อะไรเลย
Jason Sundram

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

49

หากคุณใช้ Visual Studio ใช่คุณสามารถทำได้

เครื่องมือสร้างไลบรารีที่มาพร้อมกับ Visual Studio ช่วยให้คุณสามารถรวมไลบรารีเข้าด้วยกันบนบรรทัดคำสั่ง ฉันไม่รู้วิธีทำสิ่งนี้ในโปรแกรมแก้ไขภาพ

lib.exe /OUT:compositelib.lib  lib1.lib lib2.lib

5
ใน VS2008 ในคุณสมบัติโปรเจ็กต์ของ compositelib ภายใต้ Librarian / General หากคุณตรวจสอบ [x] Link Library Dependencies มันจะทำสิ่งนี้ให้คุณถ้า lib1 และ lib2 เป็นที่พึ่งพาของ compositelib ดูเหมือนว่ามีข้อผิดพลาดเล็กน้อยฉันจะตั้งค่าช่องทำเครื่องหมายแยกกันในแต่ละการกำหนดค่าการสร้างไม่ใช่ครั้งเดียวใน "การกำหนดค่าทั้งหมด"
Spike0xff

2
VS2015 IDE - คุณไม่ได้ใช้ "การพึ่งพาเพิ่มเติม" ภายใต้ Librarian / General เพื่อรับไลบรารีเพิ่มเติมที่เชื่อมโยงโดยตรงกับไลบรารีที่โครงการของคุณกำลังสร้างอยู่ใช่หรือไม่?
davidbak

1
@davidbak ฉันพยายามคิดออกในช่วงสองสามวันที่ผ่านมาและเห็นได้ชัดว่าตัวเลือกนี้ล้าสมัยและไม่ได้ทำอะไรเลย?
Montaldo

21

บน Linux หรือ MingW พร้อม GNU toolchain:

ar -M <<EOM
    CREATE libab.a
    ADDLIB liba.a
    ADDLIB libb.a
    SAVE
    END
EOM
ranlib libab.a

ในกรณีที่คุณไม่ลบliba.aและlibb.aคุณสามารถสร้าง "ที่เก็บถาวรแบบบาง":

ar crsT libab.a liba.a libb.a

บน Windows ที่มี MSVC toolchain:

lib.exe /OUT:libab.lib liba.lib libb.lib

ยินดีที่ได้ทราบ แต่ไม่สามารถแก้ปัญหาของ OP ได้จริง ๆ เนื่องจากคุณรวมทุกอย่างตั้งแต่ libb.a ลงใน lib ร่วมซึ่งอาจมีขนาดใหญ่มากหากคุณต้องการโมดูลเพียงไม่กี่โมดูลจาก libb
Elmar Zander

1
@ElmarZander แต่คุณสามารถใช้ar crsTซึ่งทำอะไรบางอย่างเช่น "symlinking" แทนการคัดลอกคุณต้องส่งสำเนาข้อมูลเพียงชุดเดียว
Star Brilliant

ไฟล์เก็บถาวรแบบบางถูกนำมาใช้โดยเฉพาะบนเคอร์เนล Linux v4.19: unix.stackexchange.com/questions/5518/…
Ciro Santilli 郝海东冠状病六四事件法轮功

10

ไลบรารีแบบคงที่เป็นเพียงที่เก็บถาวรของ.oไฟล์อ็อบเจ็กต์ แตกไฟล์ด้วยar(สมมติว่า Unix) และแพ็คกลับเข้าไปในไลบรารีใหญ่เดียว


6

หรือLink Library Dependenciesในคุณสมบัติโครงการมีอีกวิธีหนึ่งในการเชื่อมโยงไลบรารีใน Visual Studio

  1. เปิดโปรเจ็กต์ของไลบรารี (X) ที่คุณต้องการรวมกับไลบรารีอื่น
  2. เพิ่มไลบรารีอื่น ๆ ที่คุณต้องการรวมกับ X (คลิกขวาAdd Existing Item...)
  3. ไปที่คุณสมบัติของพวกเขาและตรวจสอบให้แน่ใจว่าItem Typeเป็นLibrary

ซึ่งจะรวมไลบรารีอื่น ๆ ใน X ราวกับว่าคุณวิ่ง

lib /out:X.lib X.lib other1.lib other2.lib

สวัสดีฉันใช้ Intel IPP และฉันสร้างฟังก์ชั่นของตัวเองซึ่งฉันต้องการให้ทั้งหมดรวมเป็นหนึ่ง lib (คงที่) แต่เมื่อฉันสร้าง lib แล้วส่งโปรเจ็กต์ไปยังคอมพิวเตอร์เครื่องอื่นซึ่งฉันต้องการให้สามารถคอมไพล์โปรเจ็กต์ได้โดยใช้ lib ที่ฉันสร้างขึ้นเท่านั้นฉันได้รับข้อผิดพลาดว่าต้องมีไฟล์. h ของ Intel IPP Library ความคิดใด ๆ ?
Royi

ไฟล์ lib มักจะไม่เพียงพอ หากต้องการใช้งานคุณจะต้องรวมไฟล์ส่วนหัวด้วย แต่มันไม่อยู่ในหัวข้อนี้เนื่องจากเธรดนี้พูดถึงการเชื่อมโยงและปัญหาของคุณอยู่ในขั้นตอนการรวบรวม
evpo

ตกลง. เพื่อช่วยคุณฉันต้องการข้อมูลเพิ่มเติม ดูที่เอาต์พุตหรือบันทึกการสร้างและดูว่ามีอะไรบ่นเกี่ยวกับไฟล์. h ที่หายไป ฉันคิดว่ามันคือ cl.exe หากเป็นเช่นนั้นระบบจะให้ชื่อไฟล์. cpp / .cc / .c ที่คอมไพล์แล้วซึ่งใช้ส่วนหัว ไฟล์. cpp นั้นชื่ออะไรและเป็นของโครงการใด
evpo

ฉันสับสนมาก ก่อนที่ฉันจะอ่านสิ่งนี้ดูเหมือนว่าจะไม่ได้ผลเลย (นี่คือวิธีกำหนดค่าโครงการของฉันแล้ว) แต่ตอนนี้ฉันได้อ่านและรีเซ็ตโปรเจ็กต์ของฉันแล้วดูเหมือนว่าจะใช้งานได้ ไปคิด! :(
มอ

1
@Mordachai ไฮกุด้านล่างนี้อธิบายประสบการณ์ของคุณได้อย่างสมบูรณ์แบบ: เมื่อวานทำงานวันนี้ไม่ทำงาน Windows เป็นเช่นนั้น
evpo

6

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

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

โปรดทราบว่าสัญลักษณ์ที่รวมไว้ยังคงถูกรายงานว่าไม่ได้กำหนดโดยnmฉันจึงติดตามไฟล์ออบเจ็กต์ที่ถูกเพิ่มลงใน lib1 ด้วยตัวเองเพื่อพิจารณาว่าสามารถหยุดการวนซ้ำได้หรือไม่

#! /bin/bash

lib1="$1"
lib2="$2"

if [ ! -e $lib1.backup ]; then
    echo backing up
    cp $lib1 $lib1.backup
fi

remove_later=""

new_tmp_file() {
    file=$(mktemp)
    remove_later="$remove_later $file"
    eval $1=$file
}
remove_tmp_files() {
    rm $remove_later
}
trap remove_tmp_files EXIT

find_symbols() {
    nm $1 $2 | cut -c20- | sort | uniq 
}

new_tmp_file lib2symbols
new_tmp_file currsymbols

nm $lib2 -s --defined-only > $lib2symbols

prefix="xyz_import_"
pass=0
while true; do
    ((pass++))
    echo "Starting pass #$pass"
    curr=$lib1
    find_symbols $curr "--undefined-only" > $currsymbols
    changed=0
    for sym in $(cat $currsymbols); do
        for obj in $(egrep "^$sym in .*\.o" $lib2symbols | cut -d" " -f3); do
            echo "  Found $sym in $obj."
            if [ -e "$prefix$obj" ]; then continue; fi
            echo "    -> Adding $obj to $lib1"
            ar x $lib2 $obj
            mv $obj "$prefix$obj"
            ar -r -s $lib1 "$prefix$obj"
            remove_later="$remove_later $prefix$obj"
            ((changed=changed+1))
        done
    done
    echo "Found $changed changes in pass #$pass"

    if [[ $changed == 0 ]]; then break; fi
done

ฉันตั้งชื่อสคริปต์libcompนั้นเพื่อให้คุณสามารถเรียกมันได้เช่นกับ

./libcomp libmylib.a libwhatever.a

ที่ใดก็ตามที่คุณต้องการรวมสัญลักษณ์จาก อย่างไรก็ตามฉันคิดว่าการคัดลอกทุกอย่างลงในไดเร็กทอรีแยกต่างหากจะปลอดภัยที่สุดก่อน ฉันจะไม่เชื่อถือสคริปต์ของฉันมากนัก (อย่างไรก็ตามมันใช้ได้ผลสำหรับฉันฉันสามารถรวม libgsl.a ไว้ในไลบรารีตัวเลขของฉันด้วยสิ่งนั้นและทิ้งสวิตช์คอมไพเลอร์ -lgsl นั้นไว้)


ยอดเยี่ยมมาก สำหรับโปรเจ็กต์ขนาดใหญ่ (> สัญลักษณ์ 500k ในวัตถุ> 40k ในไลบรารีดั้งเดิมซึ่งฉันต้องการสัญลักษณ์ ~ 1,000 ตัว) สิ่งนี้ใช้เวลาเกือบหนึ่งชั่วโมงในขณะที่ gcc สามารถทำสิ่งเดียวกันได้โดยใช้การเชื่อมโยงแบบไดนามิกในไม่กี่วินาที มีเหตุผลพื้นฐานบางประการที่ทำให้เครื่องมือคอมไพเลอร์ไม่ง่ายกว่านี้หรือไม่?
ZachB
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.