Điều này là để bổ sung cho câu trả lời của @ Horstling.
Bạn có thể tạo ra một tĩnh hoặc một động thư viện. Khi bạn tạo các thư viện liên kết tĩnh, mã được biên dịch cho tất cả các hàm/đối tượng sẽ được lưu vào một tệp (với phần mở rộng .lib trong Windows). Tại dự án chính của dự án (thời gian sử dụng thư viện), các mã này sẽ được liên kết vào tệp thực thi cuối cùng của bạn cùng với các mã dự án chính. Vì vậy, thực thi cuối cùng sẽ không có bất kỳ sự phụ thuộc thời gian chạy nào.
Thư viện được liên kết động sẽ được hợp nhất vào dự án chính vào thời gian chạy (và không phải thời gian liên kết). Khi bạn biên dịch thư viện, bạn nhận được một tệp .dll (chứa mã được biên dịch thực tế) và tệp .lib (chứa đủ dữ liệu cho trình biên dịch/thời gian chạy để tìm các hàm/đối tượng trong tệp .dll). Tại thời gian liên kết, tệp thực thi sẽ được định cấu hình để tải .dll và sử dụng mã được biên dịch từ .dll đó khi cần. Bạn sẽ cần phải phân phối các tập tin .dll với thực thi của bạn để có thể chạy nó.
Không cần phải chọn giữa liên kết tĩnh hoặc động (hoặc chỉ tiêu đề) khi thiết kế thư viện của bạn, bạn tạo nhiều dự án/makefiles, một để tạo một tệp .lib tĩnh, một để tạo tệp .lib/.dll ghép đôi và phân phối cả hai phiên bản, để người dùng lựa chọn giữa. (Bạn sẽ cần phải sử dụng các macro tiền xử lý như macro @Horstling được đề xuất).
Bạn không thể đặt bất kỳ mẫu trong thư viện trước khi biên soạn, trừ khi bạn sử dụng một kỹ thuật gọi là Explicit õ, làm hạn chế các thông số mẫu.
Cũng lưu ý rằng trình biên dịch/liên kết hiện đại thường không tôn trọng công cụ sửa đổi nội tuyến. Họ có thể nội tuyến một chức năng ngay cả khi nó không được chỉ định là nội tuyến, hoặc có thể tự động gọi một người khác có sửa đổi nội tuyến, khi họ thấy phù hợp. (Bất kể, tôi sẽ tư vấn đặt nội tuyến một cách rõ ràng khi áp dụng cho khả năng tương thích tối đa). Vì vậy, sẽ không có bất kỳ hình phạt hiệu suất thời gian chạy nào nếu bạn sử dụng thư viện được liên kết tĩnh thay vì thư viện chỉ tiêu đề (và cho phép tối ưu hóa trình biên dịch/liên kết). Như những người khác đã đề xuất, đối với các chức năng thực sự nhỏ chắc chắn được hưởng lợi từ việc được gọi là nội dòng, cách tốt nhất là đặt chúng vào tệp tiêu đề, do đó thư viện được liên kết động cũng sẽ không bị mất hiệu suất đáng kể. (Trong mọi trường hợp, các chức năng nội tuyến sẽ chỉ ảnh hưởng đến hiệu suất cho các hàm được gọi rất thường xuyên, các vòng lặp bên trong sẽ được gọi là hàng nghìn/triệu lần).
Thay vì đặt các chức năng nội tuyến trong các tập tin tiêu đề (với một #include "foo.cpp"
trong tiêu đề của bạn), bạn có thể thay đổi makefile/thiết lập dự án và thêm Foo.cpp vào danh sách các file nguồn được biên dịch. Bằng cách này, nếu bạn thay đổi bất kỳ việc thực hiện chức năng nào sẽ không cần phải biên dịch lại toàn bộ dự án và chỉ foo.cpp mới được biên dịch lại. Như tôi đã đề cập trước đó, các chức năng nhỏ của bạn sẽ vẫn được biên dịch bởi trình biên dịch tối ưu hóa, và bạn không cần phải lo lắng về điều đó.
Nếu bạn sử dụng/thiết kế thư viện được biên dịch trước, bạn nên xem xét trường hợp thư viện được biên dịch với một phiên bản trình biên dịch khác cho dự án chính. Mỗi phiên bản trình biên dịch khác nhau (thậm chí là các cấu hình khác nhau, như Debug hoặc Release) sử dụng thời gian chạy C khác nhau (như memcpy, printf, fopen, ...) và thời gian chạy thư viện chuẩn C++ (như std :: vector <>, std :: chuỗi, ...). Các triển khai thư viện khác nhau này có thể làm phức tạp liên kết, hoặc thậm chí tạo ra các lỗi thời gian chạy.
Theo nguyên tắc chung, luôn tránh chia sẻ đối tượng thời gian chạy trình biên dịch (cấu trúc dữ liệu không được định nghĩa theo tiêu chuẩn, như FILE *) trên thư viện, vì cấu trúc dữ liệu không tương thích sẽ dẫn đến lỗi thời gian chạy.
Khi liên kết dự án của bạn, các hàm thời gian chạy C/C++ phải được liên kết với thư viện của bạn .lib hoặc .lib/.dll hoặc tệp .exe của bạn. Bản thân thời gian chạy C/C++ có thể được liên kết như là thư viện tĩnh hoặc động (bạn có thể thiết lập nó trong các thiết lập makefile/project).
Bạn sẽ thấy liên kết động với thời gian chạy C/C++ trong cả thư viện và dự án chính (ngay cả khi bạn biên dịch thư viện như thư viện tĩnh) tránh hầu hết các sự cố liên kết (với các triển khai hàm trùng lặp trong nhiều phiên bản thời gian chạy) . Tất nhiên bạn sẽ cần phải phân phối thời gian chạy DLL cho tất cả các phiên bản sử dụng với thực thi của bạn và thư viện.
Có các trường hợp liên kết tĩnh với thời gian chạy C/C++, và cách tốt nhất trong các trường hợp này là biên dịch thư viện với cài đặt trình biên dịch giống như dự án chính để tránh các vấn đề liên kết.
Bạn đang nói về loại thư viện nào? Thư viện vùng chứa thường là một tập hợp mẫu và các mẫu này phải là "chỉ tiêu đề". Một thư viện ứng dụng khác nhau. –
@BasileStarynkevitch: Ví dụ: [this] (https://github.com/SuperV1234/SSVUtils) là một trong các thư viện chỉ tiêu đề của tôi. Nó chủ yếu dựa trên mẫu, nhưng cũng có các mô-đun không dựa vào các khuôn mẫu (ví dụ, mô-đun 'CommandLine'). Thay đổi một dòng trong khi phát triển trong một trong các mô-đun không phải mẫu đòi hỏi biên dịch lại đầy đủ. Ngoài ra, thực tế là giao diện và thực hiện không tách biệt làm phiền tôi. Bạn có nghĩ loại thư viện này là một ứng cử viên cho ý tưởng của tôi được mô tả trong câu hỏi không? –
Điểm số 1 của bạn là vô nghĩa. Nếu thư viện là chỉ tiêu đề, tôi không thể liên kết nó, đúng. (Trừ khi tôi viết thư viện wrapper của riêng mình xung quanh nó). Và nếu bạn làm cho nó trở thành một thư viện động, tôi không thể chỉ '# include' nó. Nó cắt giảm cả hai cách. – jalf