Liên kết các thư viện tĩnh với các thư viện tĩnh khác


138

Tôi có một đoạn mã nhỏ phụ thuộc vào nhiều thư viện tĩnh (a_1-a_n). Tôi muốn đóng gói mã đó trong một thư viện tĩnh và cung cấp cho người khác.

Thư viện tĩnh của tôi, hãy gọi nó là X, biên dịch tốt.

Tôi đã tạo một chương trình mẫu đơn giản sử dụng hàm từ X, nhưng khi tôi cố liên kết nó với X, tôi gặp nhiều lỗi về các ký hiệu bị thiếu từ các thư viện a_1 - a_n.

Có cách nào để tôi có thể tạo một thư viện tĩnh mới, Y chứa X và tất cả các chức năng cần thiết của X (các bit được chọn từ a_1 - a_n), để tôi có thể phân phối Y cho mọi người để liên kết các chương trình của họ không?


CẬP NHẬT:

Tuy nhiên, tôi đã xem xét việc bỏ tất cả mọi thứ với ar và tạo ra một mega-lib, tuy nhiên, kết thúc bao gồm rất nhiều biểu tượng không cần thiết (tất cả các tệp .o khoảng 700 MB, tuy nhiên, một tệp thực thi được liên kết tĩnh là 7 MB). Có một cách tốt đẹp để chỉ bao gồm những gì thực sự cần thiết?


Điều này có vẻ liên quan chặt chẽ với Làm thế nào để kết hợp một số thư viện C / C ++ thành một? .

Câu trả lời:


76

Thư viện tĩnh không liên kết với các thư viện tĩnh khác. Cách duy nhất để làm điều này là sử dụng công cụ thủ thư / lưu trữ của bạn (ví dụ ar trên Linux) để tạo một thư viện tĩnh mới bằng cách ghép nhiều thư viện.

Chỉnh sửa: Đáp lại cập nhật của bạn, cách duy nhất tôi biết để chỉ chọn các ký hiệu được yêu cầu là tạo thư viện theo cách thủ công từ tập hợp con của các tệp .o có chứa chúng. Điều này là khó khăn, tốn thời gian và dễ bị lỗi. Tôi không biết về bất kỳ công cụ nào để giúp làm điều này (không nói rằng chúng không tồn tại), nhưng nó sẽ tạo ra một dự án khá thú vị để sản xuất một công cụ.


Xin chào Neil, tôi đã cập nhật câu hỏi - bạn có biết cách nào chỉ bao gồm các tệp .o cần thiết không?
Jason Sundram

Cập nhật - Nếu bạn thấy mình muốn làm điều này, hãy lùi lại một bước và theo đuổi thứ khác (trừ khi, như John Knoeller chỉ ra, bạn đang sử dụng Visual Studio). Tôi đã dành rất nhiều thời gian cho phương pháp này và không nhận được bất cứ điều gì hữu ích.
Jason Sundram

Công cụ GNU ld cung cấp một tùy chọn -rvới đầu ra có thể được sử dụng làm đầu vào cho ld. Nếu bạn liên kết một lần, bạn sẽ nhận được một di dời, có thể thay thế thư viện của bạn. (đã thử nó thogh).
harper

49

Nếu bạn đang sử dụng Visual Studio thì có, bạn có thể làm điều này.

Công cụ xây dựng thư viện đi kèm với Visual Studio cho phép bạn kết hợp các thư viện với nhau trên dòng lệnh. Tôi không biết cách nào để làm điều này trong trình soạn thảo trực quan.

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

5
Trong VS2008, trong các thuộc tính dự án của compositelib theo Librarian / General, nếu bạn kiểm tra [x] Phụ thuộc thư viện liên kết, nó sẽ thực hiện điều này cho bạn nếu lib1 và lib2 là phụ thuộc của compositelib. Có vẻ hơi lỗi, tôi sẽ đặt hộp kiểm riêng trong từng cấu hình bản dựng, không chỉ một lần trong 'Tất cả Cấu hình'.
Spike0xff

2
IDE VS2015 - bạn không sử dụng "Phụ thuộc bổ sung" trong Thư viện / Tổng hợp để nhận các thư viện bổ sung được liên kết trực tiếp vào thư viện mà dự án của bạn đang xây dựng?
davidbak

@davidbak Tôi đang cố gắng tìm hiểu điều này trong vài ngày qua và rõ ràng tùy chọn này đã lỗi thời và không làm gì cả?
Montaldo

20

Trên Linux hoặc MingW, với chuỗi công cụ GNU:

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

Nếu bạn không xóa liba.alibb.a, bạn có thể tạo một "kho lưu trữ mỏng":

ar crsT libab.a liba.a libb.a

Trên Windows, với chuỗi công cụ MSVC:

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

Rất vui được biết, nhưng không thực sự giải quyết được vấn đề của OP, vì bạn đã bao gồm mọi thứ từ libb.a vào lib chung, có thể trở nên rất lớn nếu bạn chỉ cần một vài mô-đun từ libb.
Elmar Zander

1
@ElmarZander Nhưng bạn có thể sử dụng ar crsT, hoạt động như "symlinking" thay vì sao chép, thì bạn chỉ cần gửi một bản sao dữ liệu.
Sao rực rỡ

Tài liệu lưu trữ mỏng được sử dụng đáng chú ý trên nhân Linux v4.19: unix.stackexchange.com/questions/5518/ Kẻ
Ciro Santilli 冠状 六四 事件

10

Một thư viện tĩnh chỉ là một kho lưu trữ các .otệp đối tượng. Trích xuất chúng bằng ar(giả sử Unix) và gói chúng trở lại vào một thư viện lớn.


5

Ngoài ra, Link Library Dependenciestrong các thuộc tính của dự án, có một cách khác để liên kết các thư viện trong Visual Studio.

  1. Mở dự án của thư viện (X) mà bạn muốn kết hợp với các thư viện khác.
  2. Thêm các thư viện khác mà bạn muốn kết hợp với X (Nhấp chuột phải, Add Existing Item...).
  3. Đi đến tài sản của họ và chắc chắn Item TypeLibrary

Điều này sẽ bao gồm các thư viện khác trong X như thể bạn đã chạy

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

Xin chào, tôi đang sử dụng Intel IPP và tôi đã xây dựng các chức năng của riêng mình mà tôi muốn tất cả được gói gọn trong một lib (Tĩnh). Tuy nhiên, khi tôi tạo lib và sau đó gửi dự án tới máy tính khác mà tôi muốn có thể biên dịch dự án chỉ bằng lib tôi đã tạo, tôi gặp lỗi khi yêu cầu phải có tệp .h của Thư viện Intel IPP. Bất kỳ ý tưởng?
Royi

tập tin lib thường không đủ. Nếu bạn muốn sử dụng nó, bạn cũng cần bao gồm các tệp tiêu đề. Nhưng nó không có chủ đề ở đây vì chủ đề này nói về liên kết và vấn đề của bạn đang ở giai đoạn biên dịch.
evpo 27/2/2015

đồng ý. Để giúp bạn tôi sẽ cần thêm thông tin. Nhìn vào đầu ra bản dựng hoặc nhật ký và xem những gì phàn nàn về tệp .h bị thiếu. Tôi nghĩ đó là cl.exe. Nếu đó là trường hợp, nó sẽ cung cấp cho bạn tên của tệp .cpp / .cc / .c được biên dịch sử dụng tiêu đề. Tên của tệp .cpp đó là gì và nó thuộc về dự án nào?
evpo

Tôi bối rối quá. Trước khi tôi đọc nó, nó dường như chưa từng hoạt động (đây là cách các dự án của tôi đã được cấu hình). Nhưng bây giờ tôi đã đọc nó và thiết lập lại các dự án của mình, nó dường như đang hoạt động. Đi đi! :(
Mordachai

1
@Mordachai haiku dưới đây mô tả trải nghiệm của bạn một cách hoàn hảo: Hôm qua nó hoạt động Hôm nay nó không hoạt động Windows là như thế
evpo

5

Lưu ý trước khi bạn đọc phần còn lại: Kịch bản shell hiển thị ở đây chắc chắn không an toàn để sử dụng và được kiểm tra tốt. Sử dụng có nguy cơ của riêng bạn!

Tôi đã viết một kịch bản bash để hoàn thành nhiệm vụ đó. Giả sử thư viện của bạn là lib1 và thư viện bạn cần bao gồm một số ký hiệu là lib2. Tập lệnh bây giờ chạy trong một vòng lặp, nơi đầu tiên nó kiểm tra các ký hiệu không xác định từ lib1 có thể được tìm thấy trong lib2. Sau đó, nó trích xuất các tệp đối tượng tương ứng từ lib2 ar, đổi tên chúng một chút và đặt chúng vào lib1. Bây giờ có thể có nhiều biểu tượng bị thiếu hơn, bởi vì những thứ bạn đưa vào từ lib2 cần những thứ khác từ lib2, mà chúng tôi chưa bao gồm, vì vậy vòng lặp cần phải chạy lại. Nếu sau một số lần vượt qua của vòng lặp không còn thay đổi nữa, tức là không có tệp đối tượng nào từ lib2 được thêm vào lib1, vòng lặp có thể dừng lại.

Lưu ý rằng các ký hiệu được bao gồm vẫn được báo cáo là không xác định bởi nmvì vậy tôi đang theo dõi các tệp đối tượng, được thêm vào lib1, để xác định xem vòng lặp có thể dừng được không.

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

Tôi đặt tên cho kịch bản đó libcomp, vì vậy bạn có thể gọi nó sau đó, ví dụ như với

./libcomp libmylib.a libwhatever.a

nơi libwhthing là nơi bạn muốn bao gồm các biểu tượng từ. Tuy nhiên, tôi nghĩ an toàn nhất là sao chép mọi thứ vào một thư mục riêng trước. Tôi sẽ không tin vào kịch bản của mình rất nhiều (tuy nhiên, nó hoạt động với tôi; tôi có thể đưa libgsl.a vào thư viện số của mình với điều đó và bỏ qua trình chuyển đổi trình biên dịch -lgsl).

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.