Существует ли путь к 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
Согласно этой странице:
Если символ будет определен в двух различных библиотеках gcc, то будет использовать первый, который он находит, и проигнорируйте второй, если второй не включен в объектный файл, который включен по некоторой другой причине.
Так вышеупомянутое поведение имеют смысл. К сожалению, я наследовал значительную кодовую базу, которая не использует пространства имен (и добавление их не выполнимо прямо сейчас), и использует некоторые универсальные имена классов всюду по нескольким библиотекам. Я хотел бы автоматически обнаружить двойные названия во время ссылки, чтобы удостовериться, что неправильная копия класса случайно не является инстанцированием. Что-то как:
# g++ -Wl,--warnLibraryDupSymbols main.o FakePort.a Port.a
Warning: Duplicate symbol: Port
но я ничего не могу найти в опциях компоновщика GCC сделать это. Действительно ли возможно заставить GCC автоматически обнаруживать и сообщать о таких случаях?
Возможно, стоит попробовать следующее (честно говоря, я не знаю, будет ли это делать то, что вы хотите):
--whole-archive
Для каждого архива, упомянутого в командной строке после опции --whole-archive, включите в ссылку каждый объектный файл из архива, вместо того чтобы искать в архиве нужные объектные файлы. Обычно это используется для превращения архивного файла в разделяемую библиотеку, заставляя каждый объект быть включенным в результирующую разделяемую библиотеку. Эта опция может быть использована более одного раза.
Я не пробовал, но похоже, что он будет включать все объекты в библиотеку, как если бы они были объектными файлами. Вам нужно будет указать эту опцию для каждой библиотеки.
Как сказал Нил, это не даст вам конфликтов на уровне классов, но если есть члены класса с одинаковой сигнатурой, это может заставить компоновщик сообщить вам об этом.
Нет, не существует. Причина этого в том, что имя класса не является символом для компоновщика. Компилятор C ++ будет использовать имя класса для создания искаженных имен функций, но само имя класса исчезнет к моменту включения компоновщика.
В качестве альтернативы вы можете использовать скрипт, использующий 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'])
Я тоже не вижу никаких вариантов, чтобы делать то, что вы хотите. Возможно, подумайте горизонтально и используйте инструмент документации кода, такой как Doxygen, чтобы создать документацию для всех ваших классов и вручную искать дубликаты