Menghubungkan perpustakaan statis ke perpustakaan statis lainnya

138

Saya memiliki sepotong kecil kode yang tergantung pada banyak perpustakaan statis (a_1-a_n). Saya ingin mengemas kode itu di perpustakaan statis dan membuatnya tersedia untuk orang lain.

Pustaka statis saya, sebut saja X, kompilasi dengan baik.

Saya telah membuat contoh program sederhana yang menggunakan fungsi dari X, tetapi ketika saya mencoba menautkannya ke X, saya mendapatkan banyak kesalahan tentang simbol yang hilang dari pustaka a_1 - a_n.

Apakah ada cara saya bisa membuat perpustakaan statis baru, Y yang berisi X dan semua fungsionalitas yang diperlukan oleh X (bit yang dipilih dari a_1 - a_n), sehingga saya bisa mendistribusikan Y hanya untuk orang-orang untuk menautkan program mereka?


MEMPERBARUI:

Saya telah melihat hanya membuang semuanya dengan ar dan membuat satu mega-lib, namun, yang akhirnya termasuk banyak simbol yang tidak diperlukan (semua file .o sekitar 700 MB, namun, executable yang terhubung secara statis adalah 7 MB). Apakah ada cara yang baik untuk memasukkan hanya apa yang sebenarnya dibutuhkan?


Ini terlihat terkait erat dengan Bagaimana menggabungkan beberapa perpustakaan C / C ++ menjadi satu? .

Jason Sundram
sumber

Jawaban:

76

Perpustakaan statis tidak terhubung dengan perpustakaan statis lainnya. Satu-satunya cara untuk melakukan ini adalah dengan menggunakan alat / pengarsipan pustakawan Anda (misalnya ar di Linux) untuk membuat perpustakaan statis single baru dengan menggabungkan yang beberapa perpustakaan.

Sunting: Menanggapi pembaruan Anda, satu-satunya cara yang saya tahu untuk memilih hanya simbol yang diperlukan adalah secara manual membuat perpustakaan dari subset file .o yang berisi mereka. Ini sulit, memakan waktu dan rawan kesalahan. Saya tidak mengetahui adanya alat untuk membantu melakukan ini (tidak untuk mengatakan mereka tidak ada), tetapi itu akan membuat proyek yang cukup menarik untuk menghasilkan satu.


sumber
Hai Neil, saya telah memperbarui pertanyaan - apakah Anda tahu cara memasukkan hanya file .o yang diperlukan?
Jason Sundram
Pembaruan - Jika Anda menemukan diri Anda ingin melakukan ini, mundur selangkah, dan mengejar sesuatu yang lain (kecuali, seperti yang ditunjukkan oleh John Knoeller, Anda menggunakan Visual Studio). Saya banyak tenggelam dalam pendekatan ini dan tidak mendapatkan sesuatu yang bermanfaat.
Jason Sundram
Alat GNU ld memberikan opsi -rbahwa output dapat digunakan sebagai input untuk ld. Jika Anda menautkan sekali Anda harus mendapatkan relokasi, itu bisa menjadi pengganti perpustakaan Anda. (Sudah mencobanya thogh).
harper
49

Jika Anda menggunakan Visual Studio maka ya, Anda bisa melakukan ini.

Alat pembuat perpustakaan yang dilengkapi dengan Visual Studio memungkinkan Anda untuk bergabung dengan perpustakaan bersama di baris perintah. Saya tidak tahu cara untuk melakukan ini di editor visual.

lib.exe /OUT:compositelib.lib  lib1.lib lib2.lib
John Knoeller
sumber
5
Dalam VS2008, dalam properti proyek compositelib di bawah Pustakawan / Umum, jika Anda memeriksa [x] Tautan Dependensi Perpustakaan, itu akan melakukan ini untuk Anda jika lib1 dan lib2 adalah dependensi dari compositelib. Tampaknya agak buggy, saya akan mengatur kotak centang secara terpisah di setiap konfigurasi build, tidak sekali di 'Semua Konfigurasi'.
Spike0xff
2
VS2015 IDE - tidakkah Anda menggunakan "Ketergantungan Tambahan" di bawah Pustakawan / Umum untuk mendapatkan perpustakaan tambahan yang terhubung langsung ke perpustakaan yang sedang dibangun proyek Anda?
davidbak
@davidbak Saya mencoba mencari tahu dalam beberapa hari terakhir dan tampaknya opsi ini sudah usang dan tidak melakukan apa-apa?
Montaldo
20

Di Linux atau MingW, dengan GNU toolchain:

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

Jika Anda tidak menghapus liba.adan libb.a, Anda dapat membuat "arsip tipis":

ar crsT libab.a liba.a libb.a

Di Windows, dengan MSVC toolchain:

lib.exe /OUT:libab.lib liba.lib libb.lib
Bintang Brilliant
sumber
Senang mengetahui, tetapi tidak benar-benar menyelesaikan masalah OP, karena Anda memasukkan semuanya dari libb.a ke dalam lib bersama, yang dapat menjadi sangat besar jika Anda hanya membutuhkan beberapa modul dari libb.
Elmar Zander
1
@ Elmarander Tapi Anda dapat menggunakan ar crsT, yang melakukan sesuatu seperti "symlinking" daripada menyalin, maka Anda hanya perlu mengirimkan satu salinan data.
Bintang Cemerlang
Arsip tipis terutama digunakan pada kernel Linux v4.19: unix.stackexchange.com/questions/5518/…
Ciro Santilli 郝海东 冠状 病 六四 六四 事件
10

Pustaka statis hanyalah arsip dari .ofile objek. Ekstrak mereka dengan ar( dengan asumsi Unix) dan kemas kembali ke satu perpustakaan besar.

Nikolai Fetissov
sumber
6

Atau ke Link Library Dependenciesdalam properti proyek ada cara lain untuk menautkan pustaka di Visual Studio.

  1. Buka proyek perpustakaan (X) yang ingin Anda gabungkan dengan perpustakaan lain.
  2. Tambahkan perpustakaan lain yang ingin Anda gabungkan dengan X (Klik Kanan, Add Existing Item... ).
  3. Pergi ke properti mereka dan memastikan Item TypeadalahLibrary

Ini akan termasuk perpustakaan lain di X seolah-olah Anda berlari

lib /out:X.lib X.lib other1.lib other2.lib
evpo
sumber
Hai, saya menggunakan Intel IPP dan saya membangun fungsi saya sendiri yang saya ingin semua dibungkus menjadi satu (statis) lib. Namun ketika saya membuat lib dan kemudian mengirim proyek ke komputer lain yang saya ingin dapat mengkompilasi proyek hanya menggunakan lib yang saya buat saya mendapatkan kesalahan mengatakan file .h dari Perpustakaan Intel IPP diperlukan. Ada ide?
Royi
File lib biasanya tidak cukup. Jika Anda ingin menggunakannya, Anda harus memasukkan file header juga. Tapi di sini bukan topik karena utas ini berbicara tentang menautkan dan masalah Anda berada pada tahap kompilasi.
evpo
baik. Untuk membantu Anda, saya akan memerlukan informasi lebih lanjut. Lihatlah output build atau log dan lihat apa yang mengeluh pada file .h yang hilang. Saya pikir itu adalah cl.exe. Jika demikian, ini akan memberi Anda nama file .cpp / .cc / .c yang dikompilasi yang menggunakan header. Apa nama file .cpp itu dan proyek milik siapa?
evpo
Aku sangat bingung. Sebelum saya membaca ini, sepertinya tidak pernah berhasil (ini adalah bagaimana proyek saya sudah dikonfigurasi). Tapi sekarang saya sudah membaca ini dan mengatur ulang proyek saya, ternyata berhasil. Sosok pergi! :(
Mordachai
1
@Machachai haiku ini di bawah ini menggambarkan pengalaman Anda dengan sempurna: Kemarin berfungsi Hari ini tidak berfungsi Windows seperti itu
evpo
5

Catatan sebelum Anda membaca sisanya: Script shell yang ditampilkan di sini tentu tidak aman untuk digunakan dan diuji dengan baik. Gunakan dengan risiko Anda sendiri!

Saya menulis skrip bash untuk menyelesaikan tugas itu. Misalkan perpustakaan Anda adalah lib1 dan yang Anda perlu menyertakan beberapa simbol dari adalah lib2. Script sekarang berjalan dalam satu loop, di mana ia pertama kali memeriksa simbol yang tidak terdefinisi dari lib1 dapat ditemukan di lib2. Ini kemudian mengekstrak file objek yang sesuai dari lib2 dengan ar, mengubah nama mereka sedikit, dan menempatkannya ke lib1. Sekarang mungkin ada lebih banyak simbol yang hilang, karena hal-hal yang Anda sertakan dari lib2 membutuhkan hal-hal lain dari lib2, yang belum kami sertakan, sehingga loop perlu dijalankan kembali. Jika setelah melewati beberapa loop tidak ada perubahan lagi, yaitu tidak ada file objek dari lib2 ditambahkan ke lib1, loop dapat berhenti.

Perhatikan, bahwa simbol yang disertakan masih dilaporkan sebagai tidak terdefinisi oleh nm, jadi saya melacak file objek, yang ditambahkan ke lib1, sendiri, untuk menentukan apakah loop dapat dihentikan.

#! /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

Saya menamai skrip itu libcomp, sehingga Anda dapat memanggilnya misalnya dengan

./libcomp libmylib.a libwhatever.a

dari mana libwhever adalah tempat Anda ingin menyertakan simbol. Namun, saya pikir paling aman untuk menyalin semuanya ke direktori yang terpisah terlebih dahulu. Saya tidak akan terlalu mempercayai skrip saya (namun, itu berhasil untuk saya; Saya bisa memasukkan libgsl.a ke dalam perpustakaan numerik saya dengan itu dan meninggalkan saklar kompiler -lgsl).

Elmar Zander
sumber