Автоматически генерировать зависимости объектного файла (компоновщика) для исполняемых файлов C / C ++

В настоящее время я работаю над гибкой средой сборки C / C ++, которую (надеюсь) скоро открою. (увидетьэтот вопрос для некоторого фона).

Я использую приведенную ниже команду для генерации зависимостей файла #include для файлов исходного кода / заголовка.

gcc -M -MM -MF

Есть ли способ умело выводить зависимости компоновщика (.o файл) дляexecutables (модульные тесты + основной исполняемый файл для целевой платформы в моем случае) с использованием утилит gcc / GNU аналогично описанному выше? В настоящее время структура делает много предположений и довольно глупа в определении этих зависимостей.

Я слышал об одном подходе, гдеnm Команда может быть использована для создания списка неопределенных символов в объектном файле. Например, при запуске nm в объектном файле (скомпилированном с помощью gcc -c) получается что-то вроде этого -

nm -o module.o

module.o:         U _undefinedSymbol1
module.o:         U _undefinedSymbol2
module.o:0000386f T _definedSymbol

Затем можно было бы искать другие объектные файлы, где эти неопределенные символыare определено для составления списка зависимостей объектных файлов, необходимых для успешного связывания файла.

Считается ли это наилучшей практикой при определении зависимостей компоновщика для исполняемых файлов? Есть ли другие способы вывести эти зависимости? Предположим, что все объектные файлы уже существуют (т.е. уже скомпилированы с использованием gcc -c) при предложении вашего решения.

 Oliver Charlesworth20 мая 2012 г., 04:53
Что станет отправной точкой для этого подхода? У вас изначально нет объектных файлов, и поэтому вам не с чемnm...
 thegreendroid20 мая 2012 г., 04:54
Предположим, что все файлы были скомпилированы (то есть непосредственно перед процессом связывания), и их соответствующие объектные файлы уже существуют.
 Oliver Charlesworth20 мая 2012 г., 05:00
Да, но вам не нужен один объектный файл для создания другого объектного файла. Вам нужны объектные файлы для создания исполняемого файла (или разделяемой библиотеки). Таким образом, вершиной вашего дерева зависимостей будет исполняемый файл. Если вы не знаете, каковы зависимости исполняемого файла, то вы ничего не можете сделать.
 Oliver Charlesworth20 мая 2012 г., 04:55
В этом случае нет никаких зависимостей для разрешения. Если B является зависимостью от A, это означает, что B требуется для того, чтобыcreate A.
 thegreendroid20 мая 2012 г., 04:58
Я использую gcc-c Возможность компилировать все файлы, но не ссылки.

Ответы на вопрос(3)

nm вывод для всех объектных файлов в текущем каталоге:

#! /usr/bin/env python

import collections
import os
import re
import subprocess

addr_re = r"(?P<address>[0-9a-f]{1,16})?"
code_re = r"(?P<code>[a-z])"
symbol_re = r"(?P<symbol>[a-z0-9_.$]+)"
nm_line_re = re.compile(r"\s+".join([addr_re, code_re, symbol_re]) + "\s*$",
                        re.I)

requires = collections.defaultdict(set)
provides = collections.defaultdict(set)

def get_symbols(fname):
    lines = subprocess.check_output(["nm", "-g", fname])
    for l in lines.splitlines():
        m = nm_line_re.match(l)
        symbol = m.group('symbol')
        if m.group('code') == 'U':
            requires[fname].add(symbol)
        else:
            provides[symbol].add(fname)

for dirpath, dirnames, filenames in os.walk("."):
    for f in filenames:
        if f.endswith(".o"):
            get_symbols(f)

def pick(symbols):
    # If several files provide a symbol, choose the one with the shortest name.
    best = None
    for s in symbols:
        if best is None or len(s) < len(best):
            best = s
    if len(symbols) > 1:
        best = "*" + best
    return best

for fname, symbols in requires.items():
    dependencies = set(pick(provides[s]) for s in symbols if s in provides)
    print fname + ': ' + ' '.join(sorted(dependencies))

Скрипт ищет текущий каталог и все подкаталоги для.o файлы, звонкиnm для каждого найденного файла и анализирует полученный результат. Символы, которые не определены в одном.o Файл и определяется в другом интерпретируются как зависимость между двумя файлами. Символы, определенные нигде (обычно предоставляемые внешними библиотеками), игнорируются. Наконец, скрипт выводит список прямых зависимостей для всех объектных файлов.

Если символ предоставляется несколькими объектными файлами, этот сценарий произвольно предполагает зависимость от объектного файла с самым коротким именем файла (и помечает выбранный файл как* в выходной). Это поведение можно изменить, изменив функциюpick.

Скрипт работает для меня в Linux и MacOS, я не пробовал другие операционные системы, и скрипт только слегка протестирован.

 30 нояб. 2017 г., 19:32
Спасибо за публикацию этого. Я наткнулся здесь, пытаясь ответить на немного другой вопрос - в приложении, которое разумно не управляет своими зависимостями, как я могу выяснить, действительно ли что-то НУЖНО связать с определенной библиотекой или объектным файлом. Мне, вероятно, придется изменить ваш сценарий, но его всегда легче создать поверх чего-либо, чем создать заново.
 30 нояб. 2017 г., 20:02
Кроме того, по крайней мере с Python 2.7 это не работает без изменений. В цикле возврата из os.walk () я должен был присоединитьсяdirpath а такжеf чтобы получить путь к файлу, и передать путь к файлу в качестве аргументаget_symbols.

такие как библиотеки .a), используя libbfd. Я думаю, что вы действительно хотите сделать, это обработать базу данных открытых символов, определенных в библиотеках, о которых вы знаете, и в объектных файлах, которые являются частью этого проекта, так что при создании каждого нового объектного файла вы можете посмотреть на неопределенные символы в нем и определить, какой объект - обычный или в библиотеке - вам нужно создать ссылку для разрешения ссылок. По сути, вы выполняете ту же работу, что и компоновщик, но в некотором роде наоборот, чтобы определить, какие символы вы можете найти.

Если вы работаете с GCC, вы всегда можете заглянуть в пакеты с исходными текстами для вашего "binutils". найти источники в нм, и даже в лд, если вы этого хотите. Вы, конечно, не хотите запускать nm и анализировать вывод, когда он просто использует libbfd под капотом, просто вызовите libbfd самостоятельно.

 thegreendroid26 сент. 2012 г., 03:12
Я этого не знал, отличный совет! Спасибо @Wexxor!
Решение Вопроса

й файл), которым требуются разные наборы зависимостей, тогда обычный, классический способ обработки - использование библиотеки & # x2014; статический.a или поделился.so (или эквивалентный) & # x2014; хранить объектные файлы, которые могут использоваться более чем одной программой, и связывать программы с этой библиотекой. Компоновщик автоматически извлекает правильные объектные файлы из статического архива. Процесс с общей библиотекой немного отличается, но общий результат тот же: исполняемый файл имеет правильные объектные файлы, доступные ему во время выполнения.

Для любой программы существует, по меньшей мере, один файл, уникальный для этой программы (обычно это файл, который содержитmain() программа). Там может быть несколько файлов для этой программы. Эти файлы, вероятно, известны и могут быть легко перечислены. Те из них, которые вам могут понадобиться в зависимости от конфигурации и параметров компиляции, вероятно, используются совместно программами и легко обрабатываются с помощью механизма библиотеки.

Вы должны решить, хотите ли вы использовать статические или общие библиотеки. Хорошо создать общие библиотеки сложнее, чем создавать статические библиотеки. С другой стороны, вы можете обновить общую библиотеку и сразу же повлиять на все программы, которые ее используют, тогда как статическая библиотека может быть изменена, но изменения принесут пользу только тем программам, которые связаны с новой библиотекой.

Ваш ответ на вопрос