2010-05-04 31 views
11

Có cách nào để GCC đưa ra cảnh báo trong khi liên kết các thư viện có chứa các lớp có cùng tên không? Ví dụLiên kết các thư viện với các tên lớp trùng lặp bằng GCC

Port.h

class Port { 
public: 
    std::string me(); 
}; 

Port.cpp

#include "Port.h" 
std::string Port::me() { return "Port"; } 

FakePort.h

class Port { 
public: 
    std::string me(); 
}; 

FakePort.cpp

#include "FakePort.h" 
std::string Port::me() { return "FakePort"; } 

main.cpp

#include "Port.h" 

int main() { 
    Port port; 
    std::cout << "Hello world from " << port.me() << std::endl; 
    return 0; 
} 

Building

# g++ -c -o Port.o Port.cpp 
# ar rc Port.a Port.o 
# g++ -c -o FakePort.o FakePort.cpp 
# ar rc FakePort.a FakePort.o 
# g++ -c -o main.o main.cpp 
# g++ main.o Port.a FakePort.a 
# ./a.out 
    Hello world from Port 

Thay đổi thư viện để

# g++ main.o FakePort.a Port.a 
# ./a.out 
    Hello world from FakePort 

Theo this page:

Nếu một biểu tượng được định nghĩa trong hai thư viện gcc khác nhau sẽ sử dụng cái đầu tiên mà nó tìm thấy và bỏ qua một giây trừ khi cái thứ hai được bao gồm trong một tập tin đối tượng mà được bao gồm vì một số lý do khác.

Vì vậy, hành vi trên có ý nghĩa. Thật không may tôi đang thừa kế một cơ sở mã khá lớn mà không sử dụng không gian tên (và thêm chúng không khả thi ngay bây giờ) và sử dụng một số tên lớp chung chung trong nhiều thư viện. Tôi muốn tự động phát hiện tên trùng lặp tại thời gian liên kết để đảm bảo rằng bản sao sai của một lớp không phải là vô tình đang được instantiating. Một cái gì đó như:

# g++ -Wl,--warnLibraryDupSymbols main.o FakePort.a Port.a 
    Warning: Duplicate symbol: Port 

nhưng tôi không thể tìm thấy bất kỳ điều gì trong tùy chọn trình liên kết GCC để thực hiện điều đó. Liệu GCC có thể tự động phát hiện và báo cáo các trường hợp như vậy không?

+0

liên quan: http://stackoverflow.com/questions/10671956/same-class-name-in-different-c-files – oliver

Trả lời

3

Sau đây có thể là đáng thử (Thực sự tôi không biết nếu nó sẽ làm những gì bạn muốn):

--whole-archive

Đối với mỗi lưu trữ nêu trên dòng lệnh sau - tùy chọn -whole-archive, bao gồm mọi tệp đối tượng trong tệp lưu trữ trong liên kết, thay vì tìm kiếm tệp lưu trữ cho các tệp đối tượng được yêu cầu. Điều này thường được sử dụng để biến một tệp lưu trữ thành một thư viện được chia sẻ, buộc mọi đối tượng phải được bao gồm trong thư viện được chia sẻ kết quả. Tùy chọn này có thể được sử dụng nhiều lần.

Tôi chưa thử, nhưng có vẻ như nó sẽ kéo tất cả các mục trong thư viện như thể chúng là các tệp đối tượng. Bạn sẽ cần chỉ định tùy chọn cho mỗi thư viện.

Như Neil đã nói, điều này sẽ không cung cấp cho bạn xung đột cấp lớp, nhưng nếu có thành viên lớp học có cùng chữ ký, điều này có thể làm cho trình liên kết cho bạn biết.

+0

Không chắc nếu điều này là tốt nhất câu trả lời chung, nhưng nó hoạt động ở đây. # g ++ main.cpp -Wl, - toàn bộ lưu trữ FakePort.a Port.a -Wl, - không toàn bộ lưu trữ Port.a (Port.o): Port.cpp :(. Text + 0x0) : nhiều định nghĩa của 'Port :: me() 'FakePort.a (FakePort.o): FakePort.cpp: (. văn bản + 0x0): đầu tiên được xác định ở đây – joesdiner

+1

Nếu tôi không thiếu bất cứ điều gì này có thể bloat nhị phân của bạn đáng kể, vì vậy nó chỉ hữu ích cho chạy thử. Hoặc có thể chăm sóc điều đó bằng '--no-whole-archive' ở đúng chỗ không? @joesdiner –

+1

@gf: Tôi nghĩ bạn đúng; mục đích của câu trả lời này là sử dụng điều này để chẩn đoán các vấn đề (hoặc các vấn đề tiềm năng) ở giai đoạn tích hợp - không phải là cấu hình xây dựng bình thường. Tôi nghĩ đây là những gì joesdiner đang tìm cách làm. –

0

Tôi không thấy bất kỳ tùy chọn nào để thực hiện những gì bạn muốn. Có thể suy nghĩ về sau và sử dụng công cụ tài liệu mã như Doxygen để tạo tài liệu cho tất cả các lớp học của bạn và tìm kiếm bản sao theo cách thủ công

0

Không có. Lý do cho điều này là một tên lớp không phải là một biểu tượng như xa như mối liên kết là có liên quan. Trình biên dịch C++ sẽ sử dụng tên lớp để tạo ra các tên hàm bị xáo trộn, nhưng tên lớp chính nó đã biến mất khi mà trình liên kết được tham gia.

1

Hoặc bạn có thể sử dụng tập lệnh sử dụng nm để tìm các ứng viên, ví dụ: cái gì đó như:

import collections, subprocess, os, re, sys 

def filt(s): 
    p = subprocess.Popen(['c++filt', s],stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
    return p.communicate()[0].strip() 

rx = re.compile('^[\\d\\w]+ T [\\w]+', re.MULTILINE) 
sym = collections.defaultdict(set) 

for file in sys.argv[1:]: 
    proc = subprocess.Popen(['nm', file], stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
    for s in rx.findall(proc.communicate()[0]): 
    sym[s.split()[2]].add(file) 

for s in filter(lambda x: len(sym[x])>1, sym): 
    print 'Duplicate "%s" in %s' % (filt(s), str(sym[s])) 

foo:$ python dups.py *.a 
Duplicate "Port::me()" in set(['Port.a', 'FakePort.a']) 
+0

Sử dụng tập lệnh như thế này để tạo danh sách các ứng viên song công và sau đó làm việc trên các tệp makefiles của bạn. Tạo các mẫu makefile tập trung vào một nhóm các lớp đã biết trong đó chúng đặt hàng các đường dẫn bao gồm được cấu trúc. Bằng cách đó nó dễ dàng hơn để theo dõi 'Port' nào đang được liên kết –

+0

Kịch bản hay. Làm việc cho tôi, nhưng tùy chọn liên kết được cung cấp bởi Michael Burr dường như tự động phát hiện mọi thứ – joesdiner

+0

@ joesdiner: Thậm chí tốt hơn. Đáng buồn là '--whole-archive' không hoạt động đối với tôi trên OSX. –

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