Связывание библиотек с повторяющимися именами классов с помощью 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 автоматически обнаруживать и сообщать о таких случаях?

4 ответа

Решение

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

--whole-archive

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

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

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

В качестве альтернативы вы можете использовать скрипт, использующий 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, для генерации документации для всех ваших классов и поиска дубликатов вручную.

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

Другие вопросы по тегам