Процесс компиляции

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

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

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

Я уже:

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

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

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

Шаг 1:

  • вход: исходный код(с)
  • процесс: разбор (возможно, добавить более подробную информацию здесь)
  • Output: все, что выводится здесь..

Шаг 2:

  • Input: что было выведено из Шага 1, плюс, возможно, что-то еще нужно (библиотеки? Dll? .так? .Либ? )
  • процесс: все, что делается с помощью ввода
  • выход: все, что выход

и так на..

спасибо..

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

спасибо.. Прости, что был таким придурком..

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

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

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

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

5 ответов


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

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

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

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

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

в качестве примера, рассмотрим следующий упрощенный код C (xx.c) и команду.

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

cc -c -o xx.obj xx.c

компиляция до xx.obj. The bob.h содержит прототип для bob_fn() так что компиляция будет успешной. The -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 (The lib and .так добавляются линкером обычно). В этом примере -L задает путь для поиска библиотек. The -l указывает библиотеку для включения в исполняемый файл, если необходимый. Компоновщик обычно берет " Боб " и находит первый соответствующий файл библиотеки в пути поиска, указанном -L.

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

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

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

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

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

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


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

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

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

  • вход:
    • объектный файл[s] с шага 1
    • библиотеки других объектов (например, из O/S и другого программного обеспечения)

два основных шага-компиляция и связывание.

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

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

теперь, чтобы объяснить что-то о "extern" C", вам нужно:

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