2012-04-09 33 views
7

Tôi đã làm việc với và thử nghiệm một tên đăng ký lưu tự, nhà máy trừu tượng dựa trên một mô tả ở đây:nối tự đăng ký lại, trừu tượng nhà máy

https://stackoverflow.com/a/582456

Trong mọi trường hợp thử nghiệm của tôi, nó hoạt động giống như một sự quyến rũ, và cung cấp các tính năng và tái sử dụng mà tôi muốn.

Liên kết trong nhà máy này trong dự án của tôi bằng cách sử dụng cmake đã khá phức tạp (mặc dù nó có vẻ là nhiều hơn một vấn đề ar).

Tôi có base.hpp, derivedb.hpp/cpp giống hệt nhau và một tệp deriveda.hpp/cpp tương đương với ví dụ được liên kết. Trong chính, tôi chỉ đơn giản là khởi tạo nhà máy và gọi createInstance() hai lần, một lần với "DerivedA" và "DerivedB".

Các thực thi được tạo ra bởi dòng:

g++ -o testFactory main.cpp derivedb.o deriveda.o 

công trình như mong đợi. Di chuyển các lớp thừa kế của tôi vào một thư viện (sử dụng cmake, nhưng tôi đã thử nghiệm điều này với ar mình cũng) và sau đó kết nối thất bại:

ar cr libbase.a deriveda.o derivedb.o 
g++ -o testFactory libbase.a main.cpp 

chỉ gọi instantiation đầu tiên tĩnh (từ derivedA.cpp) và không bao giờ thứ hai instantiation tĩnh, tức là

// deriveda.cpp (if listed first in the "ar" line, this gets called) 
DerivedRegister<DerivedA> DerivedA::reg("DerivedA"); 

// derivedb.cpp (if listed second in the "ar" line, this does not get called) 
DerivedRegister<DerivedB> DerivedB::reg("DerivedB"); 

Lưu ý rằng trao đổi hai trong dòng ar gọi chỉ derivedb.cpp instantiation tĩnh, và không phải là deriveda.cpp instantiation.

Tôi có thiếu thứ gì đó với thư viện ar hoặc tĩnh mà bằng cách nào đó không chơi tốt với các biến tĩnh trong C++?

Trả lời

10

Trái với trực giác, bao gồm lưu trữ trong lệnh liên kết không giống như bao gồm tất cả các tệp đối tượng nằm trong tệp lưu trữ. Chỉ những tệp đối tượng trong lưu trữ cần thiết để giải quyết các ký hiệu không xác định được bao gồm. Đây là một điều tốt nếu bạn xem xét rằng một khi không có liên kết động và nếu không thì toàn bộ các thư viện (nghĩ rằng thư viện C) sẽ được sao chép vào mỗi tệp thực thi. Đây là những gì man page ld (1) (GNU ld trên linux) phải nói:

Trình liên kết sẽ tìm kiếm một lưu trữ chỉ một lần, tại vị trí được chỉ định trên dòng lệnh. Nếu kho lưu trữ định nghĩa một biểu tượng không xác định trong một số đối tượng xuất hiện trước khi lưu trữ trên dòng lệnh, trình liên kết sẽ bao gồm (các) tệp thích hợp từ tệp lưu trữ. Tuy nhiên, một biểu tượng không xác định trong một đối tượng xuất hiện sau này trên dòng lệnh sẽ không làm cho trình liên kết tìm kiếm kho lưu trữ một lần nữa.

Rất tiếc, không có cách thức chuẩn để bao gồm mọi thành viên của lưu trữ trong tệp thi hành được liên kết. Trên linux, bạn có thể sử dụng g++ -Wl,-whole-archive và trên Mac OS X, bạn có thể sử dụng g++ -all_load.

Vì vậy, với binutils GNU ld, lệnh liên kết nên

g++ -o testFactory -Wl,-whole-archive libbase.a -Wl,-no-whole-archive main.cpp 

các -Wl,-no-whole-archive đảm bảo rằng bất kỳ lưu trữ xuất hiện sau này trong lệnh liên kết cuối cùng được tạo ra bởi g ++ sẽ được liên kết theo cách thông thường.

+0

Cảm ơn nhiều, điều này đặt tôi vào đúng con đường. Để tham khảo trong tương lai, điều này cũng giúp ích (nhờ cải tiến tìm kiếm-foo trên toàn bộ kho lưu trữ!) http://stackoverflow.com/a/842770/1322752 –

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