2010-05-04 23 views
11

GCC在鏈接包含具有相同名稱的類的庫時是否有辦法產生警告?例如使用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; 
} 

大廈

# 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 

更改庫順序

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

根據this page

如果符號被在兩個不同的庫的gcc將使用它找到的第一個,並忽略第二個定義,除非所述第二個被包括在被包括在對象文件出於其他原因。

所以上述行爲是有道理的。不幸的是,我繼承了一個不使用命名空間的大規模代碼庫(並且現在添加它們是不可行的),並且在多個庫中使用了一些泛型類名。我想在鏈接時自動檢測重名,以確保類的錯誤副本不會意外地被實例化。就像:

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

但我找不到任何的GCC鏈接器選項來做到這一點。是否有可能讓GCC自動檢測並報告這種情況?

+0

相關:http://stackoverflow.com/questions/10671956/same-class-name-in-different-c-files – oliver 2017-05-12 11:28:01

回答

3

下可能是值得一試(老實說,我不知道這是否會做你想要什麼):

--whole-archive

對於後在命令行中提到的每個存檔 - -whole-archive選項,將每個對象文件包含在鏈接中的存檔中,而不是在存檔中搜索所需的目標文件。這通常用於將存檔文件轉換爲共享庫,從而強制每個對象都包含在生成的共享庫中。該選項可能會多次使用。

我還沒有嘗試過,但它聽起來好像它將拉入庫中的所有項目,就好像它們是對象文件一樣。您需要爲每個庫指定選項。

正如尼爾所說,這不會給你類級別的衝突,但如果有相同簽名的類成員,這可能會使鏈接器告訴你。

+0

不知道這是否是最好的一般情況下的答案,但它在這裏工作。 #g ++ main.cpp -Wl, - whole-archive FakePort.a Port.a -Wl, - no-whole-archive Port.a(Port.o):Port.cpp :(.text + 0x0) :Port :: me()'FakePort.a(FakePort.o)的多重定義:FakePort.cpp :(。text + 0x0):首先在這裏定義 – joesdiner 2010-05-04 16:33:07

+1

如果我沒有丟失任何東西,這可能會使你的二進制文件大大增加,所以它只對測試運行有用。或者可以在正確的地方用'--no-whole-archive'來處理這個問題嗎? @joesdiner – 2010-05-04 17:03:09

+1

@gf:我認爲你是對的;這個答案的意圖是用它來診斷整合階段的問題(或潛在的問題) - 而不是正常的構建配置。我認爲這是joesdiner想要做的。 – 2010-05-04 17:23:20

0

我沒有看到任何選項來做你想做的事情。也許可以橫向思考,並使用像Doxygen這樣的代碼文檔工具爲您的所有課程生成文檔並手動查找重複內容

0

不,沒有。原因在於,就鏈接器而言,類名不是一個符號。 C++編譯器將使用類名稱來生成破壞的函數名稱,但類名稱本身在鏈接器涉入時已消失。

1

或者,您可以使用腳本利用nm來查找候選人,例如,是這樣的:

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

使用這樣的腳本來創建一個dup候選列表,然後處理你的makefile。創建生成文件模板,它們專注於已知的一組類,以便包含路徑是結構化的。這樣,跟蹤哪個「Port」被鏈接起來更容易。 – 2010-05-04 16:26:39

+0

Nice script。適用於我,但由邁克爾伯爾提供的鏈接器選項似乎是自動檢測事情 – joesdiner 2010-05-04 16:40:17

+0

@joesdiner:甚至更好。可悲的是'--whole-archive'在OSX上不適用於我。 – 2010-05-04 16:57:17