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

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

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

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

Я уже:

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

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

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

Шаг 1:

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

Шаг 2:

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

и так далее..

Спасибо..

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

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

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

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

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

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


person krebstar    schedule 04.02.2009    source источник
comment
steve-yegge.blogspot.com/2007/06/rich- Programmer-food.html Я где-то нашел это, что как-то объясняет это в какой-то степени..   -  person krebstar    schedule 04.02.2009


Ответы (5)


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

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

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

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

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

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

person paxdiablo    schedule 04.02.2009
comment
Вау, это хорошо .. Я принимаю это как ответ .. :) Кстати, не могли бы вы немного объяснить синтаксис, который вы использовали? что означает -lbob во второй команде? - person krebstar; 04.02.2009
comment
Готово, хотя команды, которые я упомянул, относятся к UNIX-типу. В MSVC IDE это делается по-другому, где вы задаете пути и имена библиотек в диалоговых окнах конфигурации проекта. - person paxdiablo; 04.02.2009
comment
Нет проблем, пакс, вы очень помогли :) И последнее. Итак, в среде MSVC файлы .lib — это статические библиотеки, которые должны быть включены в проект, а файлы .dll — это динамические библиотеки, которые загружаются через LoadLibrary. команда или подобное? Это единственная разница между ними? - person krebstar; 05.02.2009
comment
Кроме того, файлы dll и lib по существу одинаковы? (т.е. они содержат код функций, используемых в вашем коде) - person krebstar; 05.02.2009
comment
С концептуальной точки зрения, я думаю, ты прав, кребстар. Они просто содержат код/данные, которые нужно добавить во время компоновки (LIB) и во время загрузки (DLL). Внутренние форматы файлов могут сильно различаться. Я подозреваю, что библиотеки DLL уже могут быть наполовину преобразованы в формат типа EXE, но я могу ошибаться. - person paxdiablo; 05.02.2009

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

  • Вход: файл [ы] исходного кода
  • Процесс: Анализ исходного кода и перевод в машинный код
  • Output: Object file[s], which consist[s] of:
    • The names of symbols which are defined in this object, and which this object file "exports"
    • Машинный код, связанный с каждым символом, определенным в этом объектном файле.
    • Имена символов, которые не определены в этом объектном файле, но от которых зависит программное обеспечение в этом объектном файле и с которыми оно впоследствии должно быть связано, т.е. имена, которые этот объектный файл «импортирует»

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

  • Input:
    • Object file[s] from step 1
    • Библиотеки других объектов (например, из ОС и другого программного обеспечения)
  • Process:
    • For each object that you want to link
    • Получить список символов, которые импортирует этот объект
    • Найдите эти символы в других библиотеках
    • Свяжите соответствующие библиотеки с вашими объектными файлами
  • Выход: один исполняемый файл, который включает в себя машинный код всех ваших объектов, а также объекты из библиотек, которые были импортированы (связаны) с вашими объектами.
person ChrisW    schedule 04.02.2009
comment
ChrisW, вы знаете, как именно компоновщик находит символы в других библиотеках? Ищет ли он только указанный файл lib или его можно заставить сканировать каталог и пробовать все файлы lib? Спасибо.. - person krebstar; 04.02.2009
comment
Вы даете ему явный список имен файлов lib (и список каталогов, в которых могут быть найдены эти конкретные файлы lib): поэтому вам нужно указать/знать имена файлов lib, которые содержат символы, от которых зависит ваш источник. - person ChrisW; 04.02.2009
comment
Google нашел для меня образец программы, использующей Lua: codeproject.com/KB/library/lua. .aspx ... согласно этому образцу имя файла библиотеки lua — lua.lib. - person ChrisW; 04.02.2009

Два основных шага — это компиляция и компоновка.

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

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

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

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

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

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

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

person Jan de Vos    schedule 04.02.2009

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

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

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

person vava    schedule 04.02.2009
comment
Каталога недостаточно - нужно указать еще и файл библиотеки. - person paxdiablo; 04.02.2009

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

person none    schedule 08.06.2009
comment
Спасибо :) может когда-нибудь пригодится :) - person krebstar; 10.06.2009