Связывание библиотек с именами Duplicate Class с использованием 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

Согласно эта страница:

Если символ определен в двух разных библиотеках, gcc будет использовать первый, который он найдет и проигнорирует второй, если только второй не включен в объектный файл, который включается по какой-либо другой причине.

Таким образом, вышеизложенное поведение имеет смысл. К сожалению, я наследую значительную базу кода, которая не использует пространства имен (и добавление их сейчас практически невозможно) и использует некоторые общие имена классов в нескольких библиотеках. Я хотел бы автоматически обнаруживать повторяющиеся имена во время ссылки, чтобы убедиться, что неправильная копия класса не случайно создается. Что-то вроде:

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

но я не могу найти что-либо в настройках компоновщика GCC для этого. Можно ли заставить GCC автоматически обнаруживать и сообщать о таких случаях?

Ответ 1

Возможно, стоит попробовать (я честно не знаю, будет ли он делать то, что вы хотите):

--whole-archive

Для каждого архива, указанного в командной строке после опции -whole-archive, включайте каждый объектный файл в архив в ссылке, а не поиск в архиве для требуемых объектных файлов. Обычно это используется для превращения архивного файла в общую библиотеку, заставляя каждый объект быть включенным в итоговую общую библиотеку. Эта опция может использоваться несколько раз.

Я не пробовал, но звучит так, как будто он будет тянуть все элементы в библиотеке, как если бы они были объектными файлами. Вам нужно указать опцию для каждой библиотеки.

Как сказал Нил, это не даст вам конфликтов на уровне классов, но если есть члены класса с одной и той же сигнатурой, это может заставить компоновщик рассказать вам.

Ответ 2

В качестве альтернативы вы можете использовать script используя 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'])

Ответ 3

Я не вижу никаких вариантов делать то, что вы хотите. Возможно, подумайте в поперечном направлении и используйте инструмент документации по документации, такой как Doxygen, для создания документации для всех ваших классов и поиска в ручном режиме дубликатов.

Ответ 4

Нет, нет. Причина этого в том, что имя класса не является символом в отношении компоновщика. Компилятор С++ будет использовать имя класса для генерации названий функциональных функций, но само название класса не исчезнет к тому времени, когда задействуется компоновщик.