Как собрать библиотеку c из исходников
БлогNot. Как собрать проект C++ с github из исходников и подключить его к Visual Studio
Как собрать проект C++ с github из исходников и подключить его к Visual Studio
Благодаря менеджеру пакетов winget, уже входящему в актуальные сборки масдайки, теперь в Windows 10 можно инсталлировать приложения одной простой консольной командой (см. также доку от Микрософта).
Но мы рассмотрим сейчас ситуацию, когда у нас есть только ссылка на исходники проекта, скажем, на Гитхабе (возьмём для примера библиотеку для простых чисел primesieve) и нужно каким-то образом скомпилировать внешний проект в своей Studio, чтобы воспользоваться его возможностями в своём приложении.
В противном случае, конечно же, нестандартный include вроде этого, который вы нашли в коде-образце
работать не будет ни за что.
Первым делом скачаем все исходники внешнего проекта «как есть» в архиве .zip, для этого у нас на гитхабе есть кнопка «Download ZIP»:
Как загрузить проект с github в архиве .zip
Развернём проект, не создавая новой папки, если у вашего архиватора нет такого же пункта меню, просто сотрите предлагаемое архиватором имя новой папки, потому что папка уже есть в архиве:
Извлечь внешний проект из архива, не создавая новой папки
Если покопаться в файле readme.md проекта, как правило, можно найти инструкцию по установке (Build instructions) и даже «Detailed build instructions», где говорится, в числе прочего, и о компиляции проекта под Microsoft Visual C++:
Команды cmake для компиляции проекта со страницы документации
Откроем свой «некомпилируемый» без нужной библиотеки проект в Studio (я использую актуальную сборку версии 2019) и обратимся к команде меню Вид — Терминал. Выберем инструмент «Командная строка разработчика» (по умолчанию в новых сборках теперь выбран PowerShell, впрочем, если в документации приведены команды PowerShell, то применяйте их).
У Микрософта инструмент описан вот здесь.
Командная строка разработчика в Studio
В командной строке пишем команды из документации, но сначала, конечно, нужно перейти в ту папку, где у вас развёрнут скачанный проект. Мне понадобилось ввести в консоли следующее, завершая каждую команду нажатием Enter:
— теперь я в нужной папке, так как развернул свой архив в папку d:\temp
Далее как написано:
Можно просто копировать команды со страницы документации, в окне консоли вверху есть стандартная кнопочка «Вставить». А вот точка в записи команд имеет значение, это ссылка на текущую папку!
Ну и, конечно, для другой версии Studio будет другое указание компилятора, узнать своё можно командой
Нужный генератор будет помечен в списке «звёздочкой».
Теперь проект можно открывать в Studio и работать с ним, все нужные файлы есть в папке d:\temp\primesieve-master
Но мы хотим подключить всё, что нужно, к своему имеющемуся проекту, а не пытаться модифицировать чужую библиотеку.
- Меню Проект — Свойства, слева выбираем Свойства конфигурации, C/C++, Общие, раскрываем поле «Дополнительные каталоги включаемых файлов», говорим «Изменить» и показываем на папку D:\Temp\primesieve-master\include . В вашем проекте, как правило, тоже будет вложенная папка include .
- В том же окне выбираем Компоновщик — Общие — Дополнительные каталоги библиотек, «Изменить» и добавляем путь D:\Temp\primesieve-master\Release . Этого может оказаться мало, у вашего проекта и внешнего должны быть выбраны одинаковые конфигурации решения. Так как я выбрал Release для внешнего проекта, то и в своём проекте в списке «Конфигурации решения» (на стандартной панели инструментов) указал Release и платформу x64. Можно было работать и с Debug, но тогда и внешний проект компилируем как Debug и потом выбираем путь D:\Temp\primesieve-master\Debug .
- В списке C/C++ — Создание кода — Библиотека времени выполнения выбрал Многопоточный DLL (/MD), иначе будет «LNK2038: обнаружено несоответствие для ‘RuntimeLibrary’: значение ‘MT_StaticRelease’ не соответствует значению ‘MD_DynamicRelease’ в file.obj».
- Сам файл библиотеки, как правило имеющий тип .lib , тоже нужно прописать. Всё в том же окне свойства проекта выбираем список Компоновщик — Ввод, раскрываем список «Дополнительные зависимости», жмём «Изменить» и указываем в поле ввода имя файла библиотеки primesieve.lib
- На всякий случай, проверяем, что у нас в списке Компоновщик — Система — Подсистема, у меня там просто Консоль (/SUBSYSTEM:CONSOLE) , для других типов проектов может понадобиться изменение и этой настройки.
После этого у меня всё заработало.
Ну а конкретная задача, на которой я проверял библиотеку — печать самых длинных цепочек последовательных простых чисел, в которых разница между соседними значениями строго возрастает или строго убывает, предел счёта равен 1000000, вот сама программа:
Ответы вышли такие:
За счёт хорошо оптимизированного кода библиотеки считается всё мгновенно.
Библиотеки
Библиотеки позволяют использовать разработанный ранее программный код в различных программах. Таким образом, программист может не разрабатывать часть кода для своей программы, а воспользоваться тем, что входит в состав библиотек.
В языке программирования C код библиотек представляет собой функции, размещенные в файлах, которые скомпилированы в объектные файлы, а те, в свою очередь, объединены в библиотеки. В одной библиотеке объединяются функции, решающие определенный тип задач. Например, существует библиотека математических функций.
У каждой библиотеки должен быть свой заголовочный файл, в котором должны быть описаны прототипы (объявления) всех функций, содержащихся в этой библиотеке. С помощью заголовочных файлов вы «сообщаете» вашему программному коду, какие библиотечные функции есть и как их использовать.
При компиляции программы библиотеки подключаются линковщиком, который вызывается gcc. Если программе требуются только стандартные библиотеки, то дополнительных параметров линковщику передавать не надо (есть исключения). Он «знает», где стандартные библиотеки находятся, и подключит их автоматически. Во всех остальных случаях при компиляции программы требуется указать имя библиотеки и ее местоположение.
Библиотеки бывают двух видов — статические и динамические. Код первых при компиляции полностью входит в состав исполняемого файла, что делает программу легко переносимой. Код динамических библиотек не входит в исполняемый файл, последний содержит лишь ссылку на библиотеку. Если динамическая библиотека будет удалена или перемещена в другое место, то программа работать не будет. С другой стороны, использование динамических библиотек позволяет сократить размер исполняемого файла. Также если в памяти находится две программы, использующие одну и туже динамическую библиотеку, то последняя будет загружена в память лишь единожды.
Далее будет описан пример, в котором создается библиотека, после чего используется при создании программы.
Пример создания библиотеки
Допустим, мы хотим создать код, который в дальнейшем планируем использовать в нескольких проектах. Следовательно, нам требуется создать библиотеку. Исходный код для библиотеки было решено разместить в двух файлах исходного кода.
Также на данный момент у нас есть план первого проекта, использующего эту библиотеку. Сам проект также будет включать два файла.
В итоге, когда все будет сделано, схема каталогов и файлов будет выглядеть так:
Пусть каталоги library и project находятся в одном общем каталоге, например, домашнем каталоге пользователя. Каталог library содержит каталог source с файлами исходных кодов библиотеки. Также в library будут находиться заголовочный файл (содержащий описания функций библиотеки), статическая (libmy1.a) и динамическая (libmy2.so) библиотеки. Каталог project будет содержать файлы исходных кодов проекта и заголовочный файл с описанием функций проекта. Также после компиляции с подключением библиотеки здесь будет располагаться исполняемый файл проекта.
В операционных системах GNU/Linux имена файлов библиотек должны иметь префикс «lib», статические библиотеки — расширение *.a, динамические — *.so.
Для компиляции проекта достаточно иметь только одну библиотеку: статическую или динамическую. В образовательных целях мы получим обе и сначала скомпилируем проект со статической библиотекой, потом — с динамической. Статическая и динамическая «разновидности» одной библиотеки по-идее должны называться одинаково (различаются только расширения). Поскольку у нас обе библиотеки будут находиться в одном каталоге, то чтобы быть уверенными, что при компиляции проекта мы используем ту, которую хотим, их названия различны (libmy1 и libmy2).
Исходный код библиотеки
В файле figure.c содержатся две функции — rect() и diagonals() . Первая принимает в качестве аргументов символ и два числа и «рисует» на экране с помощью указанного символа прямоугольник заданной ширины и высоты. Вторая функция выводит на экране две диагонали квадрата («рисует» крестик).
В файле text.c определена единственная функция, принимающая указатель на символ строки. Функция выводит на экране звездочки в количестве, соответствующем длине указанной строки.
Заголовочный файл можно создать в каталоге source, но мы лучше сохраним его там, где будут библиотеки. В данном случае это на уровень выше (каталог library). Тем самым как бы подчеркивается, что файлы исходных кодов после создания из них библиотеки вообще не нужны пользователям библиотек, они нужны лишь разработчику библиотеки. А вот заголовочный файл библиотеки требуется для ее правильного использования.
Создание статической библиотеки
Статическую библиотеку создать проще, поэтому начнем с нее. Она создается из обычных объектных файлов путем их архивации с помощью утилиты ar.
Все действия, которые описаны ниже выполняются в каталоге library (т.е. туда надо перейти командой cd). Просмотр содержимого каталога выполняется с помощью команды ls или ls -l.
Получаем объектные файлы:
В итоге в каталоге library должно наблюдаться следующее:
Далее используем утилиту ar для создания статической библиотеки:
Параметр r позволяет вставить файлы в архив, если архива нет, то он создается. Далее указывается имя архива, после чего перечисляются файлы, из которых архив создается.
Объектные файлы нам не нужны, поэтому их можно удалить:
В итоге содержимое каталога library должно выглядеть так:
, где libmy1.a — это статическая библиотека.
Создание динамической библиотеки
Объектные файлы для динамической библиотеки компилируются особым образом. Они должны содержать так называемый позиционно-независимый код (position independent code). Наличие такого кода позволяет библиотеке подключаться к программе, когда последняя загружается в память. Это связано с тем, что библиотека и программа не являются единой программой, а значит как угодно могут располагаться в памяти относительно друг друга. Компиляция объектных файлов для динамической библиотеки должна выполняться с опцией -fPIC компилятора gcc:
В отличие от статической библиотеки динамическую создают при помощи gcc указав опцию -shared:
Использованные объектные файлы можно удалить:
В итоге содержимое каталога library:
Использование библиотеки в программе
Исходный код программы
Теперь в каталоге project (который у нас находится на одном уровне файловой иерархии с library) создадим файлы проекта, который будет использовать созданную библиотеку. Поскольку сама программа будет состоять не из одного файла, то придется здесь также создать заголовочный файл.
Функция data() запрашивает у пользователя данные, помещая их в массив strs. Далее вызывает библиотечную функцию diagonals() , которая выводит на экране «крестик». После этого на каждой итерации цикла вызывается библиотечная функция text() , которой передается очередной элемент массива; функция text() выводит на экране звездочки в количестве равному длине переданной через указатель строки.
Обратите внимание на то, как подключается заголовочный файл библиотеки: через относительный адрес. Две точки обозначают переход в каталог на уровень выше, т.е. родительский по отношению к project, после чего путь продолжается во вложенный в родительский каталог library. Можно было бы указать абсолютный путь, например, «/home/pl/c/les22/library/mylib.h». Однако при перемещении каталогов библиотеки и программы на другой компьютер или в другой каталог адрес был бы уже не верным. В случае с относительным адресом требуется лишь сохранять расположение каталогов project и library относительно друг друга.
Здесь два раза вызывается библиотечная функция rect() и один раз функция data() из другого файла проекта. Чтобы сообщить функции main() прототип data() также подключается заголовочный файл проекта.
Файл project.h содержит всего одну строчку:
Из обоих файлов проекта с исходным кодом надо получить объектные файлы для объединения их потом с файлом библиотеки. Сначала мы получим исполняемый файл, содержащий статическую библиотеку, потом — связанный с динамической библиотекой. Однако с какой бы библиотекой мы не компоновали объектные файлы проекта, компилируются они как для статической, так и динамической библиотеки одинаково:
При этом не забудьте сделать каталог project текущим!
Компиляция проекта со статической библиотекой
Теперь в каталоге project есть два объектных файла: main.o и data.o. Их надо скомпилировать в исполняемый файл project, объединив со статической библиотекой libmy1.a. Делается это с помощью такой команды:
Начало команды должно быть понятно: опция -o указывает на то, что компилируется исполняемый файл project из объектных файлов.
Помимо объектных файлов проекта в компиляции участвует и библиотека. Об этом свидетельствует вторая часть команды: -L../library -lmy1. Здесь опция -L указывает на адрес каталога, где находится библиотека, он и следует сразу за ней. После опции -l записывается имя библиотеки, при этом префикс lib и суффикс (неважно .a или .so) усекаются. Обратите внимание, что после данных опций пробел не ставится.
Опцию -L можно не указывать, если библиотека располагается в стандартных для данной системы каталогах для библиотек. Например, в GNU/Linux это /lib/, /urs/lib/ и др.
Запустив исполняемый файл project и выполнив программу, мы увидим на экране примерно следующее:
Посмотрим размер файла project:
Его размер равен 8698 байт.
Компиляция проекта с динамической библиотекой
Теперь удалим исполняемый файл и получим его уже связанным с динамической библиотекой. Команда компиляции с динамической библиотекой выглядит так (одна команда разбита на две строки с помощью обратного слэша и перехода на новую строку):
Здесь в отличии от команды компиляции со статической библиотеки добавлены опции для линковщика: -Wl,-rpath. /library/. -Wl — это обращение к линковщику, -rpath — опция линковщика, ../library/ — значение опции. Получается, что в команде мы два раза указываем местоположение библиотеки: один раз с опцией -L, а второй раз с опцией -rpath. Видимо для того, чтобы понять, почему так следует делать, потребуется более основательно изучить процесс компиляции и компоновки программ на языке C.
Следует заметить, что если вы скомпилируете программу, используя приведенную команду, то исполняемый файл будет запускаться из командной строки только в том случае, если текущий каталог project. Стоит сменить каталог, будет возникать ошибка из-за того, что динамическая библиотека не будет найдена. Но если скомпилировать программу так:
, т.е. указать для линковщика абсолютный адрес, то программа в данной системе будет запускаться из любого каталога.
Размер исполняемого файла проекта, связанного с динамической библиотекой, получился равным 8544 байта. Это немного меньше, чем при компиляции проекта со статической библиотекой. Если посмотреть на размеры библиотек:
, то видно, что динамическая больше статической, хотя исполняемый файл проекта со статической библиотекой больше. Это доказывает, что в исполняемом файле, связанном с динамической библиотекой, присутствует лишь ссылка на нее.
Как собирать С/С++ проекты в Microsoft Visual Studio?
В наше время open source проекты все популярнее. На площадках открытых проектов, например, на github можно найти множество полезных программ, но они не всегда имеют исполняемые файлы («exe»), поэтому я постараюсь рассказать о том, как можно собрать самостоятельно C/C++ программу, из исходников, написанную на Microsoft Visual Studio.
Первым делом нам необходимо загрузить онлайн установщик Microsoft Visual Studio, с официального сайта. Для компиляции С/С++ проектов нет необходимости во всех пакетах и можно выбрать только те, которые нам необходимы.
Установщик загрузит необходимые пакеты из интернета и установит их.
После установки Visual Studio можно убедиться, что всё работает создав тестовый проект и скомпилировав его. Для этого нажмите в меню «Файл» → «Создать» → «Проект. «
После чего появится диалог выбора типа проекта, где можно выбрать:
- Консольное приложение;
- Классическое приложение;
- Библиотеку динамической компоновки (dll);
- Статическую библиотеку;
В нашем случае для быстрой проверки подойдет консольное приложение, выбираем название и папку проекта , после чего жмём кнопку «ОК» и создается наша программа.
После этого остается остается лишь скомпилировать её, для этого нужно выбрать в меню «Сборка» и нажать на пункт «Собрать решение».
Далее наш проект скомпилируется и в папке проекта появится наш тестовый исполняемый файл («exe»).
Если всё работает как надо, то можно приступать к сборке какого-нибудь другого открытого проекта с github или другого хостинга проектов.
Первым делом нам нужно загрузить исходники проекта. На площадке github это делается довольно просто, жмем на кнопку «Code» и «Download ZIP». После чего нужно распаковать его и можно приступать к сборке.
Ищем файл с расширением «<название_проекта>.vcxproj» и запускаем его. Перед нами появится диалог в котором нам предложат обновить SDK проекта (набор библиотек для разработки, которые Microsoft периодически обновляет) и набор инструментов, жмём обновить.
Теперь наш проект можно собрать, но до сборки необходимо выбрать разрядность проекта (например, для 32 битной системы или 64 битной), а также тип сборки (отладочный режим — debug или release).
Выбираем 64 битную систему и тип сборки релиз, после чего компилируем проект. Как и ранее нужно выбрать в меню «Сборка» и нажать на пункт «Собрать решение».
Некоторые проектам требуется вручную изменить SDK и набор инструментов, на установленный у вас, для этого идём в свойства проекта, выбираем сверху типа сборки и разрядность системы и уже там изменяем SDK и набор инструментов. В выпадающем меню появляются установленные у нас версии, выбираем их и нажимаем «ОК». После чего наш проект скомпилируется.
Бывает, что проект использует сторонние библиотеки, для этого их нужно загрузить отдельно и положить в папку. Узнать путь или изменить его можно в свойстве проекта, в разделе «С/C++» → «Общие» → «Дополнительные каталоги включаемых файлов».
Бывает, что SDK или набор инструментов, в свойстве проекта не изменяется в диалоге, чтобы изменить их нужно записать номер SDK, закрыть Visual Studio и вручную, блокнотом изменить этот номер в файле проекта «<название_проекта>.vcxproj«.
При возникновении других проблем можно попробовать их загуглить, возможно, что кто-то уже сталкивался с ними и решил их.
Как собрать библиотеку из исходников под x32 разрядную систему?
Написал небольшую программу. Теперь необходимо портировать её для запуска на 32-разрядной системе. Для работы была использована библиотека cURL, которую я собрал из исходников. Как я понимаю, теперь мне нужно пересобрать ей с указанием требуемой системы (видимо, при вызове ./configure нужно указать какой-то параметр). Не могли бы вы подсказать, что именно мне нужно выполнить, для сборки библиотеки?
P.S. программа будет запускаться на процессоре armhf, если это важно.
нужно пересобрать её с указанием требуемой системы (видимо, при вызове ./configure нужно указать какой-то параметр)
Если это «нормальный» скрипт configure, то у него должен быть параметр —target=<целевая платформа> Под словом «платформа» понимается триада, разделённая знаками «-«, которая кодирует архитектуру железа, целевую ос и вариант API этой ос.
Запустите ./configure —help что бы узнать, как получить полный список поддерживаемых целей.
Но, даже если Ваш конфигуратор поддерживает необходимую Вам цель, дале не факт, что в системе установлены соответствующие кросс-утилиты.