Как собирать статические библиотеки из исходников?
Здравствуйте!
Подскажите пожалуйста, как собирать lib файлы
Книга подсказала мне, что лучше всего собирать исходники на той машине, где я собираюсь программировать, но делать такого мне не доводилось, а уж тем-более компилировать чужой код, в неизвестный мне тип файла
Структура исходников GLUT

Я вижу, что скорее всего, структура этого архива составлена по какой-то спецификации, следуя стандарту, значит и должен быть универсальный способ собирать такие архивы, подскажите пожалуйста как
- Вопрос задан более трёх лет назад
- 1408 просмотров
1 комментарий
Простой 1 комментарий
Конкретно GLUT не собирал, но другие библиотеки с открытыми исходниками регулярно приходится.
Самый простой вариант для MSVC — использовать микрософтовский менеджер пакетов vcpkg. У него уже есть в пакетах freeglut. Если это то что вам нужно, то рекомендую установить vcpkg с помощью него собрать glut и можете использовать.
Если этот вариант не подходит — изучайте документацию по сборке конкретно вашей версии под msvc. Вижу, что есть файл readme.win — там, скорее всего есть описание сборки под винду. Так же вижу файл glutmake.bat — видимо это запуск процесса сборки под винду.
Если используете mingw, то там обычно работают сценарии сборки для Linux:
.\configure
make
make install
Но я в этом случае использую msys2 + mingw — в msys2 входит свой менеджер пакетов pacman, устанавливаете нужную библиотеку с его помощью (аналогично как это делается в линуксе).
В любом случае в документации к библиотеке есть описание процесса сборки под поддерживаемые ОС с помощью поддерживаемых компиляторов. Если нет — то либо сборка тривиальна и нет зависимостей, либо этой библиотекой не стоит пользоваться.
Решения вопроса 1
Alexander Movchan @Alexander1705
У многих языков программирования системы сборки поставляются вместе с компиляторами и являються де-факто стандартом для соответсвующего языка.
Для C/C++ де-факто стандрата сборки нет, но есть несколько систем сборки, которые обычно используються:
make — очень простая утилита, но неудобно для больших проектов.
Можно определить по наличию файла Makefile. Иногда этот файл генерируеться скриптом configure.
Если есть Makefile, запускаем:
$ make
Удалить сгенерированные файлы (чтобы запустить сборку заново):
$ make clean
cmake— более высокоуровневая система сборки, генерирует проекты для IDE или те же Makefile.
Можно определить по наличию CMakeLists.txt
mkdir cmake-build # Создаём папку для сгенерированных файлов, чтобы не смешивались с исходниками # Это называеться out-of-source build cd cmake-build # Генерируем проект или Makefile cmake .. # Запускаем билд, можно просто запустить make cmake --build .
qmake — система сборки разработаная для сборки Qt и проектов использующих Qt.
Можно определить по наличию .pro файлов. Билдим так:
qmake make
В вашем случае используеться make.
Как собрать библиотеку c из исходников
БлогNot. Как собрать проект C++ с github из исходников и подключить его к Visual Studio
Как собрать проект C++ с github из исходников и подключить его к Visual Studio
P.S. В новых сборках Visual Studio проекты из репозиториев открываются просто из меню Файл — Клонировать репозиторий. В статье речь идёт о ситуации, когда так сделать невозможно.
Благодаря менеджеру пакетов winget, уже входящему в актуальные сборки масдайки, теперь в Windows 10 можно инсталлировать приложения одной простой консольной командой (см. также доку от Микрософта).
Но мы рассмотрим сейчас ситуацию, когда у нас есть только ссылка на исходники проекта, скажем, на Гитхабе (возьмём для примера библиотеку для простых чисел primesieve) и нужно каким-то образом «вручную» скомпилировать внешний проект в своей Studio, чтобы воспользоваться его возможностями в своём приложении.
В противном случае, конечно же, нестандартный include вроде этого, который вы нашли в коде-образце
#include
работать не будет ни за что.
Первым делом скачаем все исходники внешнего проекта «как есть» в архиве .zip, для этого у нас на гитхабе есть кнопка «Download ZIP»:

Как загрузить проект с github в архиве .zip
Развернём проект, не создавая новой папки, если у вашего архиватора нет такого же пункта меню, просто сотрите предлагаемое архиватором имя новой папки, потому что папка уже есть в архиве:

Извлечь внешний проект из архива, не создавая новой папки
Если покопаться в файле readme.md проекта, как правило, можно найти инструкцию по установке (Build instructions) и даже «Detailed build instructions», где говорится, в числе прочего, и о компиляции проекта под Microsoft Visual C++:

Команды cmake для компиляции проекта со страницы документации
Откроем свой «некомпилируемый» без нужной библиотеки проект в Studio (я использую актуальную сборку версии 2019) и обратимся к команде меню Вид — Терминал. Выберем инструмент «Командная строка разработчика» (по умолчанию в новых сборках теперь выбран PowerShell, впрочем, если в документации приведены команды PowerShell, то применяйте их).
У Микрософта инструмент описан вот здесь.

Командная строка разработчика в Studio
В командной строке пишем команды из документации, но сначала, конечно, нужно перейти в ту папку, где у вас развёрнут скачанный проект. Мне понадобилось ввести в консоли следующее, завершая каждую команду нажатием Enter:
d: cd \temp\primesieve-master
— теперь я в нужной папке, так как развернул свой архив в папку d:\temp
Далее как написано:
cmake -G "Visual Studio 16 2019" . cmake --build . --config Release
Можно просто копировать команды со страницы документации, в окне консоли вверху есть стандартная кнопочка «Вставить». А вот точка в записи команд имеет значение, это ссылка на текущую папку!
Ну и, конечно, для другой версии Studio будет другое указание компилятора, узнать своё можно командой
cmake -G
Нужный генератор будет помечен в списке «звёздочкой».
Если что-то пошло не так, ошибаетесь в консольных командах и получаете сообщения об ошибках кэша — сотрите файл CMakeCache.txt из папки скопированного проекта и попробуйте снова.
Теперь проект можно открывать в 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, вот сама программа:
#include #include #include #include void print_diffs(const std::vector& vec) < for (size_t i = 0, n = vec.size(); i != n; ++i) < if (i != 0) std::cout std::cout int main() < std::vector asc, desc; std::vector
Ответы вышли такие:
Longest run(s) of ascending prime gaps up to 1000000: 128981 (2) 128983 (4) 128987 (6) 128993 (8) 129001 (10) 129011 (12) 129023 (14) 129037 402581 (2) 402583 (4) 402587 (6) 402593 (8) 402601 (12) 402613 (18) 402631 (60) 402691 665111 (2) 665113 (4) 665117 (6) 665123 (8) 665131 (10) 665141 (12) 665153 (24) 665177 Longest run(s) of descending prime gaps up to 1000000: 322171 (22) 322193 (20) 322213 (16) 322229 (8) 322237 (6) 322243 (4) 322247 (2) 322249 752207 (44) 752251 (12) 752263 (10) 752273 (8) 752281 (6) 752287 (4) 752291 (2) 752293
За счёт хорошо оптимизированного кода библиотеки считается всё мгновенно.
Это задача из списка задач на простые числа
21.10.2021, 13:15 [10698 просмотров]
Как написать свою библиотеку на Си
Если ты встал на путь С/С++ разработчика, то скорее всего (помимо использования стандартной библиотеки — libc) рано или поздно вам потребуется занятся разработкой собственных библиотек. Зачем. Причин может быть несколько. Например вы написали свою структуру данных или свой алгоритм, и хотите использовать его повторно или распространять. Так же возможно вы написали несколько утилит и все они используют один и тот же кусок кода (например, как часто это бывает, логгер), и будет логично вынести этот кусок кода в отдельный модуль. Поскольку сопровождать такой код будет проще.
Реализация
И так, давайте начнем с примера. Создадим заголовочный файл somecode.h, который будет содержать объявление некоторой функции. Пусть будет простая функция которая разбивает предложение на слова и печатает каждое слово в новой строке. Простой синтетический пример.
1 2 3 4 5 6
#ifndef __SOMECODE__ #define __SOMECODE__ void print_split(char* str); #endif
И создадим файл somecode.c, в которой напишем реализацию нашей функции.
1 2 3 4 5 6 7 8 9 10 11 12
#include "somecode.h" #include #include void print_split(char* str) const char *word = strtok(str, " "); while (word != NULL) printf("> %s\n", word); word = strtok(NULL, " "); > >
Далее создадим файл main.c, где будем вызывать нашу функцию.
1 2 3 4 5 6 7 8 9 10
#include #include "somecode.h" int main(int argc, char** argv) if (argc > 1) print_split(argv[1]); > >
Давайте для начала скомпилируем это все самым обычным способом для проверки работоспособности.
- из исходных файлов получаем объектные файлы
- из объектных файлов получаем исполняемый файл
1 2 3 4 5 6 7 8 9 10 11 12
$ gcc -c -Wall -g -o somecode.o somecode.c $ gcc -c -Wall -g -o main.o main.c $ gcc -Wall -g -o a.out.1 main.o somecode.o $ ls -l $ ls -l total 40 -rwxr-xr-x 1 ainr ainr 19816 Aug 9 21:22 a.out.1 -rw-r--r-- 1 ainr ainr 123 Aug 9 21:20 main.c -rw-r--r-- 1 ainr ainr 3576 Aug 9 21:22 main.o -rw-r--r-- 1 ainr ainr 213 Aug 9 21:21 somecode.c -rw-r--r-- 1 ainr ainr 72 Aug 9 21:20 somecode.h -rw-r--r-- 1 ainr ainr 6224 Aug 9 21:21 somecode.o
Запускаем исполняемый файл и видим, что все работает.
1 2 3 4 5
$ ./a.out.1 "hello my little pony" > hello > my > little > pony
А теперь рассмотрим пример получения библиотеки и линковки его к исполняемому файлу. Для компиляции используем вызов gcc со следующими опциями.
$ gcc -Wall -g -shared -fpic -o libsomecode.so somecode.c
Из файла с расширением .c мы получаем файл с расширением .so. И так же обратите внимание, что библиотека имеет префикс lib. Еще мы видим, что появились два дополнительных аргумента -shared и -fpic. С помощью опции -shared мы говорим компилятору, что хотим получить а выходе библиотеку. А опция -fpic говорит компилятору, что объектные файлы должны содержать позиционно-независимый код (position independent code), который рекомендуется использовать для динамических библиотек.
Теперь скомпилируем наш исполняемый файл подключив к нему нашу библиотеку. Для этого нужно указать название библиотеки через опцию -l.
1 2 3
$ gcc -Wall -g -o a.out.2 main.c -lsomecode /usr/bin/ld: невозможно найти -lsomecode collect2: error: ld returned 1 exit status
И опс.. мы получили ошибку… Линкер говорит нам, что он не знает где лежит наша библиотека. С помощью опции -L указываем текущую директорию, где лежит наша библиотека и компиляция проходит успешно.
$ gcc -Wall -g -o a.out.2 main.c -lsomecode -L.
Пытаемся запустить нашу и программу и ловим еще одну ошибку в котором говорится, что в процессе загрузки динамических библиотек отсуствует наша библиотека.
$ ./a.out.2 "hello my little pony" ./a.out.2: error while loading shared libraries: libsomecode.so: cannot open shared object file: No such file or directory
По умолчанию в операционной системе есть некоторое количество стандартных директорий, где должны располагатся библиотеки. Посмотреть этот список можно так.
1 2 3 4 5 6 7 8 9 10 11 12 13
$ ld --verbose | grep SEARCH_DIR | sed "s/\;\ /\n/g" SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu") SEARCH_DIR("=/lib/x86_64-linux-gnu") SEARCH_DIR("=/usr/lib/x86_64-linux-gnu") SEARCH_DIR("=/usr/lib/x86_64-linux-gnu64") SEARCH_DIR("=/usr/local/lib64") SEARCH_DIR("=/lib64") SEARCH_DIR("=/usr/lib64") SEARCH_DIR("=/usr/local/lib") SEARCH_DIR("=/lib") SEARCH_DIR("=/usr/lib") SEARCH_DIR("=/usr/x86_64-linux-gnu/lib64") SEARCH_DIR("=/usr/x86_64-linux-gnu/lib");
Так же есть возможность задавать дополнительные директории с библиотеками с помощью переменной окружения LD_LIBRARY_PATH. С помощью утилиты ldd посмотрим от каких библиотек зависит наша программа.
1 2 3 4 5
$ ldd a.out.2 linux-vdso.so.1 (0x00007ffffe4e7000) libsomecode.so => not found libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fcf3b680000) /lib64/ld-linux-x86-64.so.2 (0x00007fcf3b897000)
Добавим в LD_LIBRARY_PATH текущую директорию.
$ export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PWD"
Видим, что наша библиотека подгрузилась.
1 2 3 4 5
ldd a.out.2 linux-vdso.so.1 (0x00007fffe2115000) libsomecode.so (0x00007f4848a6c000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4848860000) /lib64/ld-linux-x86-64.so.2 (0x00007f4848a76000)
И теперь программа запускается и работает.
1 2 3 4 5
$ ./a.out.2 "hello my little pony" > hello > my > little > pony
Если сравнить два исполняемых файла, то видим, что программа, которая использует динамическую библиотеку имеет меньший размер.
1 2 3 4 5 6 7 8 9 10
$ ls -l total 92 -rwxr-xr-x 1 ainr ainr 19816 Aug 9 21:22 a.out.1 -rwxr-xr-x 1 ainr ainr 17864 Aug 9 21:25 a.out.2 -rwxr-xr-x 1 ainr ainr 18808 Aug 9 21:24 libsomecode.so -rw-r--r-- 1 ainr ainr 123 Aug 9 21:20 main.c -rw-r--r-- 1 ainr ainr 3576 Aug 9 21:23 main.o -rw-r--r-- 1 ainr ainr 213 Aug 9 21:21 somecode.c -rw-r--r-- 1 ainr ainr 72 Aug 9 21:20 somecode.h -rw-r--r-- 1 ainr ainr 6224 Aug 9 21:23 somecode.o
Это произошло как раз за счет того, что реализация нашей функции теперь лежит за пределами нашего исполняемого файла. С помощью утилиты objdump можем глянуть внутрь бинарных файлов. И увидим, что во втором бинарном файле реализация функции отсутствует, но присутствует в библиотеке.
1 2 3 4 5 6
$ objdump -t a.out.1 | grep print_split 000000000000119c g F .text 0000000000000061 print_split $ objdump -t a.out.2 | grep print_split 0000000000000000 F *UND* 0000000000000000 print_split $ objdump -t libsomecode.so | grep print_split 0000000000001139 g F .text 0000000000000061 print_split
Разница в нашем случае может и маленькая, но в масштабах десятков и сотен файлов разница будет значительной.
Так что же мы сделали?
У нас есть исходные файлы, мы скомпилировали их, получив из них динамическую библиотеку. Далее эту библиотеку можем использовать повторно в других проектах.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
-------------------------------- --------------------------------- | Заголовочный файл | | Реализация | | (somecode.h) | | (somecode.c) | -------------------------------- --------------------------------- | | | | | void print_split(char* string);| | void print_split(char* string) | | | | < | | | | // . | | | | >| | | | | ------------------------------- --------------------------------- | | Компилируем \ / (gcc -shared -fpic -o liblog.so . ) | --------------------------------- | Динамическая библиотека | | (liblog.so) | --------------------------------- | | (gcc . -llog) --------------------------------------------- | | | ----------------------- ----------------------- ----------------------- | Утилита1 | | Утилита2 | | Утилита3 | ----------------------- ----------------------- ----------------------- | | | | | | | #include "somecode.h" | | #include "somecode.h" | | #include "somecode.h" | | | | | | | | print_split(". "); | | print_split(". "); | | print_split(". "); | | | | | | | ----------------------- ----------------------- -----------------------
Примерно те же действия вы будете делать и под windows и под мак, будут немного другие компиляторы, но идея одна.
Как собрать библиотеку из исходников под x32 разрядную систему?
Написал небольшую программу. Теперь необходимо портировать её для запуска на 32-разрядной системе. Для работы была использована библиотека cURL, которую я собрал из исходников. Как я понимаю, теперь мне нужно пересобрать ей с указанием требуемой системы (видимо, при вызове ./configure нужно указать какой-то параметр). Не могли бы вы подсказать, что именно мне нужно выполнить, для сборки библиотеки?
P.S. программа будет запускаться на процессоре armhf, если это важно.
Отслеживать
задан 23 июл 2017 в 11:11
Андрей Солодовников Андрей Солодовников
718 5 5 серебряных знаков 23 23 бронзовых знака
Вы имеете в виду libcurl (curl.haxx.se)? Обычно во всех дистрибутивах это достигается либо через механизм multilib, либо путём пересборки (для таких, как Gentoo, Buildroot, Yocto и т.п.). Скорее всего вас интересует второй случай, и скорее всего кросс-компиляция. Используйте дистрибутивы в исходниках, там всё это задаётся через общий конфигурационный файл.
23 июл 2017 в 13:56
А вообще, вопрос написан в стиле «у меня подземный стук», а именно много воды и мало конкретики.
23 июл 2017 в 13:56
armhf — это не просто «32-разрядная система», это ещё и «не-x86 система». Т.е. Ваша утилита должна быть скомпилирована под ARM, и для этого надо иметь подходящий компилятор и все необходимые библиотеки. Для начала можно погуглить «cross compiler».
24 июл 2017 в 9:04
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
нужно пересобрать её с указанием требуемой системы (видимо, при вызове ./configure нужно указать какой-то параметр)
Если это «нормальный» скрипт configure, то у него должен быть параметр —target= Под словом «платформа» понимается триада, разделённая знаками «-«, которая кодирует архитектуру железа, целевую ос и вариант API этой ос.
Запустите ./configure —help что бы узнать, как получить полный список поддерживаемых целей.
Но, даже если Ваш конфигуратор поддерживает необходимую Вам цель, дале не факт, что в системе установлены соответствующие кросс-утилиты.