2009-05-17 30 views
7

Tôi đã triển khai "hệ thống trình cắm" rất cơ bản như một phần của thư viện tĩnh tĩnh. Mỗi "trình cắm" thực hiện hỗ trợ cho một định dạng hình ảnh cụ thể, ví dụ: GIF, JPEG, vv .. Hơn nữa, tôi có một Singleton (một lớp được gọi là PluginManager) mà giữ một danh sách tất cả các plug-in có sẵn.Đăng ký đối tượng trong Thư viện tĩnh

Phần khó khăn là tôi muốn tắt/bật các trình cắm thêm bằng cách thêm hoặc xóa tệp nguồn của họ khỏi tệp dự án. Để đạt được điều này, mỗi trình cắm thêm tạo một biến toàn cầu (với các tên khác nhau) và đăng ký trình cắm thêm trong hàm tạo của lớp đó đến PluginManager.

Something như thế này cho các định dạng JPEG ...

struct JPEGPlugin 
{ 
    // constructor will register plugin 
    JPEGPlugin() 
    { 
    PluginManager::Singleton().RegisterPlugin(this); 
    } 

    // plenty of other code 
    ... 
}; 

JPEGPlugin jpeg_instance; // instantiate in global scope 

Tuy nhiên, trong khi điều này hoạt động hoàn hảo về mặt lý thuyết, nó không thành công khi liên kết thư viện tĩnh này sang mã khác để xây dựng một thực thi. Miễn là tệp thực thi này không truy cập vào các globals của plugin (như jpeg_instance), trình liên kết không thấy kết nối (anh ta hoàn toàn bỏ qua các tác dụng phụ của hàm tạo) và không bao gồm mã trong tệp thực thi cuối cùng. Nói cách khác, trình cắm JPEG không có sẵn trong ứng dụng cuối cùng.

Tôi gặp sự cố vài lần trong những năm qua và tôi luôn tìm kiếm giải pháp cho mạng. Mỗi lần, tôi chỉ tìm thấy các trang về cơ bản nói rằng đó là một vấn đề đã biết và tôi phải sống với nó.

Nhưng có thể một người nào đó trên SO biết cách thực hiện điều này?

Trả lời

2

Tôi không biết nếu điều này là một giải pháp cho các bạn cách giải quyết vấn đề này, nhưng chúng tôi đã có một vấn đề tương tự với đăng ký tĩnh của một nhà máy đối tượng và trong Visual Studio chúng tôi giải quyết bằng cách khai báo các lớp liên quan đến __declspec (dllexport), điều này là cần thiết mặc dù các thư viện liên quan không phải là dll. Nhưng nếu không có trình liên kết này sẽ bỏ qua các lớp không được tham chiếu.

Giải pháp đăng ký mà chúng tôi đã làm việc hơi khác một chút và không liên quan đến các đối tượng được phân bổ Stack. Tôi nâng các bộ phận từ CPP-đơn vị, đó cũng là nơi tôi phát hiện ra cách tiếp cận __declspec iirc.

[sửa] Chúng tôi cũng phải #include tuyên bố cho lớp đã đăng ký từ một số phần của mã.

+0

OK, tôi vừa nhận thấy chỉnh sửa của bạn - đó là một điểm quan trọng! :) –

2

Vì đây là một thư viện tĩnh, bạn có thể xem xét việc người quản lý đăng ký các plugin (thay vì các plugin tự đăng ký). Các tập tin tiêu đề có thể định nghĩa một số biểu tượng preproc (tức JPEG_PLUGIN) điều khiển hay không người quản lý đăng ký các plugin dựa trên sự bao gồm của tiêu đề:

 
#include "JpegPlugin.h" 

void PluginManager::RegisterPlugins() 
{ 
#idef JPEG_PLUGIN 
    RegisterPlugin(&jpeg_instance); 
#endif 
} 

JpegPlugin.h không nhất thiết cần phải bao gồm định nghĩa của JpegPlugin. Nó có thể là một cái gì đó như thế này:

 
#ifndef JPEG_PLUGIN_HEADER 
#define JPEG_PLUGIN_HEADER 

#if 0 // change this to 1 to use the plugin 
#define JPEG_PLUGIN 
#include "Jpeg_PluginCls.h" 
#endif 

#endif 
+1

Cảm ơn câu trả lời. Tuy nhiên, như bạn chỉ ra một mình, điều này giới thiệu một sự phụ thuộc từ người quản lý đến trình cắm thêm - điều mà tôi muốn tránh! Lý do là những người khác nên triển khai các trình cắm thêm mà không cần thay đổi lớp người quản lý. – beef2k

+1

Giải pháp ở đây không ngăn cản người dùng của lib tĩnh đăng ký plugin của riêng họ thông qua cơ chế trong ví dụ của bạn (người quản lý gọi phương thức RegisterPlugin giống như trong ví dụ ban đầu của bạn (sau khi tôi đã sửa)). Nó chỉ đảm bảo rằng các plugin được vận chuyển với (bên trong) thư viện tĩnh có sẵn cho người quản lý mà người dùng của bạn liên kết (không tự mình tham chiếu các plugin) –

1

Đây là lần theo dõi Harald Scheirich's answer.

Tôi đã thực hiện một số thử nghiệm và có vẻ như Chế độ phát hành của MSVC++ 2005 (nhưng không phải Chế độ gỡ lỗi) sẽ bật cờ /OPT:REF cho trình liên kết, theo LINK documentation, sẽ khiến mọi biểu tượng không được xử lý bị xóa khỏi EXE cuối cùng. Và, the webpage for __declspec(selectany) dường như chỉ ra rằng các nhà xây dựng cho các đối tượng toàn cầu không được coi là tham chiếu đến một đối tượng (IMHO không đúng, nhưng ở đó bạn có nó). Vì vậy, tôi đoán là vấn đề này "biến mất" để gỡ lỗi xây dựng - đó là chính xác?

Vì vậy, tôi nghĩ gợi ý của Harald về việc sử dụng __declspec(dllexport) là cách thuận tiện để đánh dấu biểu tượng là "được tham chiếu" vì nó được chỉ định bên trong mã nguồn. Nếu vì lý do nào đó mà bạn muốn tránh xuất biểu tượng, tôi nghi ngờ bạn có thể thực hiện điều tương tự bằng cách sử dụng /INCLUDE:mysymbol linker flag hoặc tắt cờ /OPT:REF.

+0

Chúng tôi đã gặp vấn đề tương tự với các bản dựng lỗi, toàn bộ hệ thống của chúng tôi cũng có chút giòn, một điều kiện khác cho việc này là tệp .h phải được đưa vào từ nơi nào đó đã đạt được. Vì vậy, vấn đề không biến mất với các bản dựng gỡ lỗi. Chỉ khác tôi có vấn đề để biến mất là khi có một tham chiếu trực tiếp trong mã được tiếp cận tĩnh từ một nơi khác. –

+0

Thú vị. Đó là một sự xấu hổ rằng nó rất khó để có được quyền này, như đăng ký một lớp học trong một nhà xây dựng của biến toàn cầu là một cách tốt đẹp, duy trì để phát triển một hệ thống plugin. –

+0

Chúng tôi đang gặp sự cố khi gỡ lỗi và phát hành bản dựng. Và không chỉ trên Visual Studio, mà còn trên GCC nữa. – beef2k

0

hãy:

  1. thêm dự án lib tĩnh như một tài liệu tham khảo cho dự án exe
  2. đặt cả của "thư viện liên kết phụ thuộc" và "Sử dụng phụ thuộc thư viện liên kết như đầu vào" là đúng.

Xem này: config

Khi "Sử dụng phụ thuộc thư viện liên kết như đầu vào" được thiết lập Yes, các liên kết hệ thống dự án trong các tập tin obj cho .libs sản xuất bởi các dự án phụ thuộc. Vì vậy, tất cả các biểu tượng được giữ lại.

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