Вопрос

Кто-нибудь может объяснить, как работает компиляция?

Кажется, я не могу понять, как работает компиляция..

Чтобы быть более конкретным, вот пример..Я пытаюсь написать некоторый код на MSVC ++ 6 для загрузки состояния Lua..

Я уже сделал это:

  • установите дополнительные каталоги для библиотеки и включите файлы в нужные каталоги
  • использовал extern "C" (потому что Lua - это только C, или я так слышал)
  • включите нужные заголовочные файлы

Но я все еще получаю некоторые ошибки в MSVC ++ 6 о неразрешенных внешних символах (для функций Lua, которые я использовал).

Как бы мне ни хотелось знать, как решить эту проблему и двигаться дальше, я думаю, для меня было бы намного лучше, если бы я пришел к пониманию лежащих в ее основе процессов, так что, может быть, кто-нибудь напишет хорошее объяснение этому?Что я хочу знать, так это сам процесс..Это могло бы выглядеть примерно так:

Шаг 1:

  • Входные данные:Исходный код (ы)
  • Процесс:Синтаксический анализ (возможно, добавьте сюда больше деталей)
  • Выходной сигнал:все, что здесь выводится..

Шаг 2:

  • Входные данные:Что бы ни было выведено с шага 1, плюс, возможно, все остальное, что необходимо (библиотеки?Библиотеки DLL?.и что?.библиотека?)
  • Процесс:что бы ни делалось с входными данными
  • Выходной сигнал:что бы ни было результатом

и так далее..

Спасибо..

Возможно, это объяснит, что такое символы, что именно такое "связывание", что такое "объектный" код или что-то еще..

Спасибо..Извини, что я такой нуб..

P.S.Это не обязательно должно зависеть от конкретного языка..Но не стесняйтесь выражать это на том языке, на котором вам удобнее всего..:)

Редактировать:Так или иначе, я смог устранить ошибки, оказывается, мне нужно вручную добавить файл .lib в проект;простое указание каталога библиотеки (где находится .библиотека) в настройках IDE или проекта не работает..

Однако приведенные ниже ответы в некоторой степени помогли мне лучше понять этот процесс.Большое спасибо!..Если кто-то все еще хочет написать подробное руководство, пожалуйста, сделайте это..:)

Редактировать:Просто для дополнительной справки, я нашел две статьи одного автора (Майк Дил), которые довольно хорошо объясняют это..:) Изучение процесса компиляции:Часть 1 Изучение процесса компиляции:Часть 2

Это было полезно?

Решение

Переход от исходного кода к исполняемому файлу обычно представляет собой двухэтапный процесс для C и связанных языков, хотя IDE, вероятно, представляет это как единый процесс.

1 / Вы создаете свой исходный код и запускаете его через компилятор.Компилятору на этом этапе нужны ваш исходный код и заголовочные файлы других материалов, с которыми вы собираетесь связать (см. Ниже).

Компиляция состоит из преобразования ваших исходных файлов в объектные файлы.Объектные файлы содержат ваш скомпилированный код и достаточно информации, чтобы знать, какие еще материалы им нужны, но нет где найти этот другой материал (например, библиотеки LUA).

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

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

В качестве примера рассмотрим следующий упрощенный код на языке Си (xx.c) и командовать.

#include <bob.h>
int x = bob_fn(7);

cc -c -o xx.obj xx.c

Это компилирует xx.c файл для xx.obj.Тот Самый bob.h содержит прототип для bob_fn() так что компиляция будет успешной.Тот Самый -c инструктирует компилятор сгенерировать объектный файл, а не исполняемый файл, и -o xx.obj задает имя выходного файла.

Но фактический код для bob_fn() находится не в заголовочном файле, а в /bob/libs/libbob.so, итак, чтобы связать, вам нужно что-то вроде:

cc -o xx.exe xx.obj -L/bob/libs;/usr/lib -lbob

Это создает xx.exe От xx.obj, используя библиотеки (которые ищутся по заданным путям) вида libbob.so (обычно библиотека и .so добавляются компоновщиком).В этом примере, -L задает путь поиска для библиотек.Тот Самый -l указывает библиотеку, которую необходимо найти для включения в исполняемый файл, если это необходимо.Компоновщик обычно берет "bob" и находит первый релевантный файл библиотеки в пути поиска, указанном -L.

Файл библиотеки на самом деле представляет собой набор объектных файлов (вроде того, как zip-файл содержит несколько других файлов, но не обязательно сжатых) - при обнаружении первого соответствующего вхождения неопределенного внешнего файла объектный файл копируется из библиотеки и добавляется в исполняемый файл точно так же, как ваш xx.obj файл.Обычно это продолжается до тех пор, пока больше не останется нерешенных внешних проблем."Соответствующая" библиотека является модификацией текста "bob", она может искать libbob.a, libbob.dll, libbob.so, bob.a, bob.dll, bob.so и так далее.Релевантность определяется самим компоновщиком и должна быть задокументирована.

Как это работает, зависит от компоновщика, но в основном это так.

1 / Все ваши объектные файлы содержат список нерешенных внешних проблем, которые им необходимо разрешить.Компоновщик собирает воедино все эти объекты и исправляет связи между ними (разрешает как можно больше внешних элементов).

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

3 / Повторяйте шаг 2 до тех пор, пока не исчезнут неразрешенные внешние файлы или не исчезнет возможность их разрешения из списка библиотек (на этом этапе находилась ваша разработка, поскольку вы не включили файл библиотеки LUA).

Сложность, о которой я упоминал ранее, заключается в динамическом связывании.Именно здесь вы связываетесь с заглушкой подпрограммы (своего рода маркером), а не с самой подпрограммой, которая позже разрешается во время загрузки (при запуске исполняемого файла).Такие вещи, как общие элементы управления Windows, находятся в этих библиотеках DLL, так что они могут изменяться без необходимости повторно связывать объекты с новым исполняемым файлом.

Другие советы

Шаг 1 - Компилятор:

  • Входные данные:Файл[ы] исходного кода
  • Процесс:Разбор исходного кода и перевод в машинный код
  • Выходной сигнал:Объектные файлы, которые состоят из:
    • Имена символов, которые определены в этом объекте и которые этот объектный файл "экспортирует"
    • Машинный код, связанный с каждым символом, определенным в этом объектном файле
    • Имена символов, которые не определены в этом объектном файле, но от которых зависит программное обеспечение в этом объектном файле и с которыми оно впоследствии должно быть связано, т.е.имена, которые "импортирует" этот объектный файл

Шаг 2 - Связывание:

  • Входные данные:
    • Объектный файл [ы] из шага 1
    • Библиотеки других объектов (например,из операционной системы и другого программного обеспечения)
  • Процесс:
    • Для каждого объекта, который вы хотите связать
    • Получите список символов, которые импортирует этот объект
    • Найдите эти символы в других библиотеках
    • Привяжите соответствующие библиотеки к вашим объектным файлам
  • Выходной сигнал:единый исполняемый файл, который включает машинный код всех ваших объектов, плюс объекты из библиотек, которые были импортированы (связаны) с вашими объектами.

Два основных этапа - это компиляция и связывание.

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

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

Теперь, чтобы объяснить кое-что о "внешней букве "С"", вам нужно:

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

В C ++, однако, есть нечто, называемое "перегрузкой функции / метода".Это означает, что имени функции больше недостаточно для ее идентификации.Поэтому компиляторы C ++ создают "имена" для функций, которые включают прототипы функции (поскольку имя плюс прототип однозначно идентифицируют функцию).Это известно как "искажение имен".

Спецификация "extern "C"" необходима, если вы хотите использовать библиотеку, которая была скомпилирована как код "C" (например, предварительно скомпилированные двоичные файлы Lua) из проекта на C ++.

Для вашей конкретной проблемы:если это все еще не работает, эти подсказки могут помочь:* были ли двоичные файлы Lua скомпилированы с использованием той же версии VC ++?* можете ли вы просто скомпилировать Lua самостоятельно, либо в рамках вашего решения VC, либо как отдельный проект в виде кода на C ++?* вы уверены, что все слова "extern "C"" указаны правильно?

Вы должны зайти в настройки проекта и добавить каталог, в котором у вас есть файлы библиотеки LUA * .lib, где-нибудь на вкладке "компоновщик".Параметр называется "включая библиотеки" или что-то в этом роде, извините, я не могу его найти.

Причина, по которой вы получаете "неразрешенные внешние символы", заключается в том, что компиляция в C ++ работает в два этапа.Сначала код компилируется, каждый cpp-файл помещается в свой собственный obj-файл, затем запускается "компоновщик" и объединяет все эти obj-файлы в exe-файл.файл .lib - это просто набор файлов .obj, объединенных вместе, чтобы немного упростить распространение библиотек.Итак, добавив все объявления "#include" и extern, вы сообщили компилятору, что где-то можно было бы найти код с этими сигнатурами, но компоновщик не может найти этот код, потому что он не знает, где они находятся.размещаются lib-файлы с фактическим кодом.

Убедитесь, что вы читали REDME библиотеки, обычно в них есть довольно подробное объяснение того, что вам пришлось сделать, чтобы включить это в свой код.

Возможно, вы также захотите проверить это: КОМПИЛЯТОР, АССЕМБЛЕР, КОМПОНОВЩИК И ЗАГРУЗЧИК:КРАТКИЙ РАССКАЗ.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top