ربط المكتبات الثابتة بالمكتبات الثابتة الأخرى

StackOverflow https://stackoverflow.com/questions/2157629

  •  23-09-2019
  •  | 
  •  

سؤال

لديّ قطعة صغيرة من الكود تعتمد على العديد من المكتبات الثابتة (A_1-A_N). أرغب في تشغيل هذا الرمز في مكتبة ثابتة وجعله متاحًا لأشخاص آخرين.

مكتبتي الثابتة ، دعنا نسميها x ، تجمع بشكل جيد.

لقد قمت بإنشاء برنامج عينة بسيط يستخدم وظيفة من X ، ولكن عندما أحاول ربطه بـ X ، أحصل على العديد من الأخطاء حول الرموز المفقودة من المكتبات A_1 - A_N.

هل هناك طريقة يمكنني من خلالها إنشاء مكتبة ثابتة جديدة ، Y تحتوي على X وجميع الوظائف التي تحتاجها X (بتات مختارة من A_1 - A_N) ، حتى أتمكن من توزيع Y فقط للأشخاص لربط برامجهم؟


تحديث:

لقد نظرت إلى مجرد إلقاء كل شيء معه AR ومع ذلك ، فإن صنع Mega-Lib ، ينتهي بما في ذلك الكثير من الرموز غير المطلوبة (جميع ملفات .o تبلغ حوالي 700 ميغابايت ، ومع ذلك ، فإن تنفيذًا مرتبطًا بشكل ثابت هو 7 ميغابايت). هل هناك طريقة لطيفة لتضمين فقط ما هو مطلوب بالفعل؟


هذا يبدو مرتبطا ارتباطا وثيقا كيفية الجمع بين عدة مكتبات C/C ++ في واحدة؟.

هل كانت مفيدة؟

المحلول

لا ترتبط المكتبات الثابتة مع المكتبات الثابتة الأخرى. الطريقة الوحيدة للقيام بذلك هي استخدام أداة أمين المكتبة/الأرشيف (على سبيل المثال AR على Linux) لإنشاء مكتبة ثابتة واحدة جديدة عن طريق تسلسل المكتبات المتعددة.

تعديل: استجابةً للتحديث الخاص بك ، فإن الطريقة الوحيدة التي أعرفها لتحديد الرموز المطلوبة فقط هي إنشاء المكتبة يدويًا من المجموعة الفرعية لملفات .o التي تحتوي عليها. هذا صعب ، يستغرق وقتًا طويلاً ومعرضًا للخطأ. لست على دراية بأي أدوات للمساعدة في القيام بذلك (لا نقول أنها غير موجودة) ، ولكنها ستجعل مشروعًا مثيرًا للاهتمام لإنتاج واحدة.

نصائح أخرى

إذا كنت تستخدم Visual Studio ثم نعم ، يمكنك القيام بذلك.

تتيح لك أداة Builder Library التي تأتي مع Visual Studio الانضمام إلى المكتبات معًا على سطر الأوامر. لا أعرف بأي طريقة للقيام بذلك في المحرر المرئي.

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

على 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

المكتبة الثابتة هي مجرد أرشيف .o ملفات الكائن. استخراجهم مع ar (على افتراض UNIX) وحزمهم مرة أخرى في مكتبة كبيرة واحدة.

بدلا من 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

ملاحظة قبل قراءة الباقي: إن البرنامج النصي Shell الموضح هنا ليس آمنًا للاستخدام واختباره جيدًا. استخدام على مسؤوليتك الخاصة!

كتبت نص باش لإنجاز هذه المهمة. لنفترض أن مكتبتك هي lib1 والواحد التي تحتاج إلى تضمين بعض الرموز من IS 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

حيث libhance هو المكان الذي تريد تضمينه من الرموز. ومع ذلك ، أعتقد أنه من الأكثر أمانًا نسخ كل شيء إلى دليل منفصل أولاً. لن أثق في البرنامج النصي الخاص بي كثيرًا (ومع ذلك ، فقد نجحت بالنسبة لي ؛ يمكنني تضمين libgsl.a في مكتبة الأرقام الخاصة بي مع ذلك واترك مفتاح مترجم lgsl).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top