Vì tôi quan sát thấy một số hành vi kỳ lạ của các biến toàn cầu trong các thư viện được nạp động, tôi đã viết bài kiểm tra sau đây.Thư viện được tải động và biểu tượng chung được chia sẻ
Lúc đầu chúng ta cần một thư viện liên kết tĩnh: Tiêu đề test.hpp
#ifndef __BASE_HPP
#define __BASE_HPP
#include <iostream>
class test {
private:
int value;
public:
test(int value) : value(value) {
std::cout << "test::test(int) : value = " << value << std::endl;
}
~test() {
std::cout << "test::~test() : value = " << value << std::endl;
}
int get_value() const { return value; }
void set_value(int new_value) { value = new_value; }
};
extern test global_test;
#endif // __BASE_HPP
và nguồn test.cpp
#include "base.hpp"
test global_test = test(1);
Sau đó, tôi đã viết một thư viện tự động nạp: library.cpp
#include "base.hpp"
extern "C" {
test* get_global_test() { return &global_test; }
}
và tải chương trình khách hàng g thư viện này: client.cpp
#include <iostream>
#include <dlfcn.h>
#include "base.hpp"
typedef test* get_global_test_t();
int main() {
global_test.set_value(2); // global_test from libbase.a
std::cout << "client: " << global_test.get_value() << std::endl;
void* handle = dlopen("./liblibrary.so", RTLD_LAZY);
if (handle == NULL) {
std::cout << dlerror() << std::endl;
return 1;
}
get_global_test_t* get_global_test = NULL;
void* func = dlsym(handle, "get_global_test");
if (func == NULL) {
std::cout << dlerror() << std::endl;
return 1;
} else get_global_test = reinterpret_cast<get_global_test_t*>(func);
test* t = get_global_test(); // global_test from liblibrary.so
std::cout << "liblibrary.so: " << t->get_value() << std::endl;
std::cout << "client: " << global_test.get_value() << std::endl;
dlclose(handle);
return 0;
}
Bây giờ tôi biên dịch thư viện nạp tĩnh với
g++ -Wall -g -c base.cpp
ar rcs libbase.a base.o
thư viện tự động nạp
g++ -Wall -g -fPIC -shared library.cpp libbase.a -o liblibrary.so
và khách hàng
g++ -Wall -g -ldl client.cpp libbase.a -o client
Bây giờ tôi quan sát: Máy khách và thư viện được nạp động có một phiên bản khác nhau của biến số global_test
. Nhưng trong dự án của tôi, tôi đang sử dụng cmake. Xây dựng kịch bản trông như thế này:
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
PROJECT(globaltest)
ADD_LIBRARY(base STATIC base.cpp)
ADD_LIBRARY(library MODULE library.cpp)
TARGET_LINK_LIBRARIES(library base)
ADD_EXECUTABLE(client client.cpp)
TARGET_LINK_LIBRARIES(client base dl)
phân tích tạo makefile
s Tôi thấy rằng cmake xây dựng cho khách hàng
g++ -Wall -g -ldl -rdynamic client.cpp libbase.a -o client
này kết thúc trong một hành vi hơi khác nhau nhưng gây tử vong: Các global_test
của khách hàng và thư viện được nạp động là như nhau nhưng sẽ bị hủy hai lần vào cuối chương trình.
Tôi có sử dụng cmake sai không? Có thể khách hàng và thư viện được tải động sử dụng cùng một global_test
nhưng không có vấn đề hủy diệt kép này không?
Phản ứng đầu tiên của tôi là đặt câu hỏi về sự cần thiết cho biến toàn cầu này. –
Ok, trong chương trình gốc của tôi, biến toàn cầu này là một hằng số được cung cấp bởi một thư viện liên kết tĩnh. Tuy nhiên, nó sẽ bị hủy hai lần trong phiên bản cmake – phlipsy
Vấn đề tương tự sẽ áp dụng cho bất kỳ mẫu đơn nào vì vậy tôi không thấy vấn đề với toàn cầu – Elemental