2012-03-18 36 views
30

Khi tải thư viện dùng chung trong Windows, LoadLibrary() gọi nguyên nhân DllMain trong thư viện để thực hiện cho mỗi quá trình mới và thư viện luồng đính kèm, và cho mỗi quá trình và thư viện chuỗi deattaches từ.Tự động thực hiện các chức năng khi tải thư viện chia sẻ

Có cơ chế tương tự cho Mac OS X, Linux và các hệ điều hành tương thích POSIX khác không?

+0

https://stackoverflow.com/q/2053029/4361073 – parasrish

Trả lời

42

Bạn có thể xác định chức năng tải cho thư viện linux bằng cơ chế .init. Điều này giống với việc chỉ định điểm nhập thời gian tải cho một tệp nhị phân (ví dụ: sử dụng thứ gì đó khác với điểm chính làm điểm nhập cho chương trình).

Khi liên kết sử dụng ld trực tiếp bạn sử dụng:

-init <function name> 

hoặc nếu bạn đang sử dụng cc/gcc để liên kết, bạn sử dụng:

-Wl,-init,<function name> 

Đây là lúc đó là mức độ đơn giản nhất.

Chỉnh sửa Đối với trình phá hủy/finalizers, bạn sử dụng cơ chế .fini. Điều này hoạt động theo cách tương tự như tùy chọn init và bạn sử dụng:

-fini <function name> 

khi gọi ld. Tính khả dụng được giới hạn ở tùy chọn -init trên nền tảng Mac OSX.

Bạn cũng sẽ có thể sử dụng cú pháp __attribute__((constructor)) cho gcc:

static void con() __attribute__((constructor)); 

void con() { 
    printf("I'm a constructor\n"); 
} 

Mà có lẽ là một cách cầm tay hơn là chỉnh với các tùy chọn liên kết. Tất cả các nhà xây dựng nên được gọi vào thời gian tải, nhưng không phụ thuộc vào thứ tự khởi tạo của chúng, dẫn đến các lỗi điên rồ và không thể sản xuất mà tốn thời gian và công sức để gỡ lỗi.

Chỉnh sửa 2 Việc sử dụng ngữ nghĩa __attribute__((constructor))/__attribute__((destructor)) là cơ chế thích hợp nhất cho ngôn ngữ lập trình C/C++.

Đối với ngôn ngữ D lập trình bạn thực sự cần sử dụng tĩnh mô-đun constructor/destructor:

static this() { 
    printf("static this for mymodule\n"); 
} 
static ~this() { 
    printf("static ~this for mymodule\n"); 
} 

Hoặc lớp constructor tĩnh:

class Foo { 
    static this() { 
     printf("static this for Foo\n"); 
    } 
} 

này được ám chỉ mạnh mẽ ở trong writing win32 DLLS và trong đặc tả ngôn ngữ relating to static constructors/destructors.

Chỉnh sửa 3 Bạn sẽ cần liên kết trong một .o để xuất các hàm khởi tạo/phá hủy, sẽ cho phép sử dụng trình khởi tạo tĩnh. Như tất cả những gì cần làm là gọi Runtime.initialize(), điều này thực sự gọi tất cả các hàm tạo/các hàm hủy tĩnh trong mã D.

Stub d mã cho initializer (trong một tập tin gọi là myshared.d):

import core.runtime; 

extern (C) { 
    void attach(); 
    void detach(); 
} 

export void attach() { 
    Runtime.initialize(); 
} 

export void detach() { 
    Runtime.terminate(); 
} 

Tạo .o cho cuống này:

dmd -m32 -c myshared.d 

Kiểm tra tên của các đính kèm/tách chức năng:

nm myshared.o 

Hiển thị (trong số các đầu ra khác):

0000001c S _D8myshared6attachFZv 
00000034 S _D8myshared6detachFZv 

mẫu mã c cho cách gọi này (gọi tắt là export.c trong trường hợp này), chúng tôi tham khảo các tên của các thói quen xuất khẩu từ my shared.o file:

extern void D8myshared6attachFZv(void); 
extern void D8myshared6detachFZv(void); 

void __attach(void) __attribute__((constructor)); 
void __detach(void) __attribute__((destructor)); 

void __attach(void) 
{ 
    D8myshared6attachFZv(); 
} 

void __detach(void) 
{ 
    D8myshared6detachFZv(); 
} 

Lưu ý rằng các tài liệu tham khảo extern void cần sử dụng tên bị xé của hàm được xuất. Các thẻ này phải khớp hoặc mã sẽ không liên kết.

biên dịch mã C sử dụng:

gcc -m32 -c export.c 

liên kết .c.o và các tập tin .d.o cùng nhau sử dụng:

cc -o libmyshared.dylib -m32 -shared myshared.o export.o -lphobos2 

Giả sử rằng các thư viện phobos2 là trong con đường tìm kiếm mối liên kết tiêu chuẩn của bạn. Các smatterings của -m32 tùy chọn cho trình biên dịch và liên kết là bởi vì phiên bản của trình biên dịch D mà tôi xây dựng tại địa phương chỉ hỗ trợ 32bit.

Điều này tạo ra .dylib có thể liên kết đến. Dường như nó hoạt động dựa trên thử nghiệm giới hạn mà tôi đã thực hiện. Dường như hỗ trợ cho các đối tượng được chia sẻ/thư viện động rất hạn chế, do đó, có một cơ hội tốt là sẽ có một trở ngại khác cần khắc phục.

+0

Có vẻ như là giải pháp của bạn là chấp nhận được nhất đối với tôi, như tôi đang viết bằng D, không phải trong C, và giải pháp của bạn không liên quan đến các công cụ cụ thể của GCC. Những thứ duy nhất được gọi trong constructor và destructor là khởi tạo và kết thúc D runtime. – toriningen

+0

Bạn cũng có thể gợi ý, cờ ld để chỉ định destructors là gì? – toriningen

+1

Tương đương với finalizer/destructor là sử dụng tùy chọn -fini . – Petesh

9

Để có một chức năng thực hiện bất cứ khi nào thư viện chia sẻ được nạp hoặc bốc dỡ, bạn có thể đánh dấu một hàm constructor và destructor sử dụng cú pháp thuộc tính GCC cụ thể:

__attribute__((constructor)) void init(void) { ... } 
__attribute__((destructor)) void fini(void) { ... } 

Bởi vì các phần khác nhau của một môi trường C phụ thuộc vào điều được khởi tạo trong mã số .init tiêu chuẩn được GCC thêm vào phía sau hậu trường, trực tiếp sử dụng -Wl,-init,<function name> có thể khiến chương trình của bạn bị lỗi.

Để biết thêm thông tin, hãy xem HOWTO Libary theo số Library constructor and destructor functions.

0

Đối với C++, bạn có thể tạo một lớp và sử dụng hàm tạo và hàm hủy của mình để khởi tạo thư viện.

Sau đó, bạn chỉ cần xác định biến cho lớp này.

Ví dụ khởi openssl trong thư viện:

class InitLibrary { 
public: 
    InitLibrary() { 
    CRYPTO_malloc_init(); // Initialize malloc, free, etc for OpenSSL's use 
    SSL_library_init(); // Initialize OpenSSL's SSL libraries 
    SSL_load_error_strings(); // Load SSL error strings 
    ERR_load_BIO_strings(); // Load BIO error strings 
    OpenSSL_add_all_algorithms(); // Load all available encryption algorithms 
    } 

    ~InitLibrary() { 
    ERR_remove_state(0); 
    CRYPTO_cleanup_all_ex_data(); 
    ENGINE_cleanup(); 
    } 
}; 

và chỉ thêm dòng này trong tập tin cpp: InitLibrary InitLib;

Các vấn đề liên quan