C++ подключение библиотеки собранной из исходников
Помогите разобраться с подключением библиотеки. Я собрал библиотеку из исходников, в результате получил некоторую иерархию файлов и папок, официальная инструкция по установке библиотеки на этом заканчивается. Если библиотека состоит из папок lib, include, bin, то как подключить ее понятно. Но тут получается более сложная структура файлов и папок. Как подключить библиотеку в подобных случаях? Пытаюсь подключить библиотеку Wt, компилятор MinGW, если это важно.
Отслеживать
задан 24 авг 2017 в 10:08
13 3 3 бронзовых знака
Все правильно сделали, осталось сделать install. В случае генератора MSVC, надо собрать проект INSTALL .
24 авг 2017 в 11:39
Из другого CMake-проекта делаете find_library() / find_directory() , чтобы найти эти либы и хедеры, и include_directories() / target_link_libraries() их.
24 авг 2017 в 12:01
Для Wt вообще готовый модуль есть. Если текст ошибки не сказал ничего полезного, то откройте файл FindWt.cmake , там будет написано какие переменные надо установить.
Библиотеки
Библиотеки позволяют использовать разработанный ранее программный код в различных программах. Таким образом, программист может не разрабатывать часть кода для своей программы, а воспользоваться тем, что входит в состав библиотек.
В языке программирования C код библиотек представляет собой функции, размещенные в файлах, которые скомпилированы в объектные файлы, а те, в свою очередь, объединены в библиотеки. В одной библиотеке объединяются функции, решающие определенный тип задач. Например, существует библиотека математических функций.
У каждой библиотеки должен быть свой заголовочный файл, в котором должны быть описаны прототипы (объявления) всех функций, содержащихся в этой библиотеке. С помощью заголовочных файлов вы «сообщаете» вашему программному коду, какие библиотечные функции есть и как их использовать.
При компиляции программы библиотеки подключаются линковщиком, который вызывается gcc. Если программе требуются только стандартные библиотеки, то дополнительных параметров линковщику передавать не надо (есть исключения). Он «знает», где стандартные библиотеки находятся, и подключит их автоматически. Во всех остальных случаях при компиляции программы требуется указать имя библиотеки и ее местоположение.
Библиотеки бывают двух видов — статические и динамические. Код первых при компиляции полностью входит в состав исполняемого файла, что делает программу легко переносимой. Код динамических библиотек не входит в исполняемый файл, последний содержит лишь ссылку на библиотеку. Если динамическая библиотека будет удалена или перемещена в другое место, то программа работать не будет. С другой стороны, использование динамических библиотек позволяет сократить размер исполняемого файла. Также если в памяти находится две программы, использующие одну и туже динамическую библиотеку, то последняя будет загружена в память лишь единожды.
Далее будет описан пример, в котором создается библиотека, после чего используется при создании программы.
Пример создания библиотеки
Допустим, мы хотим создать код, который в дальнейшем планируем использовать в нескольких проектах. Следовательно, нам требуется создать библиотеку. Исходный код для библиотеки было решено разместить в двух файлах исходного кода.
Также на данный момент у нас есть план первого проекта, использующего эту библиотеку. Сам проект также будет включать два файла.
В итоге, когда все будет сделано, схема каталогов и файлов будет выглядеть так:

Пусть каталоги library и project находятся в одном общем каталоге, например, домашнем каталоге пользователя. Каталог library содержит каталог source с файлами исходных кодов библиотеки. Также в library будут находиться заголовочный файл (содержащий описания функций библиотеки), статическая (libmy1.a) и динамическая (libmy2.so) библиотеки. Каталог project будет содержать файлы исходных кодов проекта и заголовочный файл с описанием функций проекта. Также после компиляции с подключением библиотеки здесь будет располагаться исполняемый файл проекта.
В операционных системах GNU/Linux имена файлов библиотек должны иметь префикс «lib», статические библиотеки — расширение *.a, динамические — *.so.
Для компиляции проекта достаточно иметь только одну библиотеку: статическую или динамическую. В образовательных целях мы получим обе и сначала скомпилируем проект со статической библиотекой, потом — с динамической. Статическая и динамическая «разновидности» одной библиотеки по-идее должны называться одинаково (различаются только расширения). Поскольку у нас обе библиотеки будут находиться в одном каталоге, то чтобы быть уверенными, что при компиляции проекта мы используем ту, которую хотим, их названия различны (libmy1 и libmy2).
Исходный код библиотеки
void rect(char sign, int w, int h) putchar('\n'); } for (i=0; i w; i++) putchar(sign); putchar('\n'); } void diagonals(char sign, int w) int i, j; for (i=0; i w; i++) { for (j=0; j w; j++) { if (i == j putchar('\n'); } }
В файле figure.c содержатся две функции — rect() и diagonals() . Первая принимает в качестве аргументов символ и два числа и «рисует» на экране с помощью указанного символа прямоугольник заданной ширины и высоты. Вторая функция выводит на экране две диагонали квадрата («рисует» крестик).
void text(char *ch) { while (*ch++ != '\0') putchar('*'); putchar('\n'); }
В файле text.c определена единственная функция, принимающая указатель на символ строки. Функция выводит на экране звездочки в количестве, соответствующем длине указанной строки.
void rect(char sign, int width, int height); void diagonals(char sign, int width); void text(char *ch);
Заголовочный файл можно создать в каталоге source, но мы лучше сохраним его там, где будут библиотеки. В данном случае это на уровень выше (каталог library). Тем самым как бы подчеркивается, что файлы исходных кодов после создания из них библиотеки вообще не нужны пользователям библиотек, они нужны лишь разработчику библиотеки. А вот заголовочный файл библиотеки требуется для ее правильного использования.
Создание статической библиотеки
Статическую библиотеку создать проще, поэтому начнем с нее. Она создается из обычных объектных файлов путем их архивации с помощью утилиты ar.
Все действия, которые описаны ниже выполняются в каталоге library (т.е. туда надо перейти командой cd). Просмотр содержимого каталога выполняется с помощью команды ls или ls -l.
Получаем объектные файлы:
gcc -c ./source/*.c
В итоге в каталоге library должно наблюдаться следующее:
figures.o mylib.h source text.o
Далее используем утилиту ar для создания статической библиотеки:
ar r libmy1.a *.o
Параметр r позволяет вставить файлы в архив, если архива нет, то он создается. Далее указывается имя архива, после чего перечисляются файлы, из которых архив создается.
Объектные файлы нам не нужны, поэтому их можно удалить:
rm *.o
В итоге содержимое каталога library должно выглядеть так:
libmy1.a mylib.h source
, где libmy1.a — это статическая библиотека.
Создание динамической библиотеки
Объектные файлы для динамической библиотеки компилируются особым образом. Они должны содержать так называемый позиционно-независимый код (position independent code). Наличие такого кода позволяет библиотеке подключаться к программе, когда последняя загружается в память. Это связано с тем, что библиотека и программа не являются единой программой, а значит как угодно могут располагаться в памяти относительно друг друга. Компиляция объектных файлов для динамической библиотеки должна выполняться с опцией -fPIC компилятора gcc:
gcc -c -fPIC source/*.c
В отличие от статической библиотеки динамическую создают при помощи gcc указав опцию -shared:
gcc -shared -o libmy2.so *.o
Использованные объектные файлы можно удалить:
rm *.o
В итоге содержимое каталога library:
libmy1.a libmy2.so mylib.h source
Использование библиотеки в программе
Исходный код программы
Теперь в каталоге project (который у нас находится на одном уровне файловой иерархии с library) создадим файлы проекта, который будет использовать созданную библиотеку. Поскольку сама программа будет состоять не из одного файла, то придется здесь также создать заголовочный файл.
#include #include "../library/mylib.h" void data (void) { char strs[3][30]; char *prompts[3] = { "Ваше имя: ", "Местонахождение: ", "Пунк прибытия: "}; int i; for (i=0; i3; i++) { printf("%s", prompts[i]); gets(strs[i]); } diagonals('~', 7); for (i=0; i3; i++) { printf("%s", prompts[i]); text(strs[i]); } }
Функция data() запрашивает у пользователя данные, помещая их в массив strs. Далее вызывает библиотечную функцию diagonals() , которая выводит на экране «крестик». После этого на каждой итерации цикла вызывается библиотечная функция text() , которой передается очередной элемент массива; функция text() выводит на экране звездочки в количестве равному длине переданной через указатель строки.
Обратите внимание на то, как подключается заголовочный файл библиотеки: через относительный адрес. Две точки обозначают переход в каталог на уровень выше, т.е. родительский по отношению к project, после чего путь продолжается во вложенный в родительский каталог library. Можно было бы указать абсолютный путь, например, «/home/pl/c/les22/library/mylib.h». Однако при перемещении каталогов библиотеки и программы на другой компьютер или в другой каталог адрес был бы уже не верным. В случае с относительным адресом требуется лишь сохранять расположение каталогов project и library относительно друг друга.
#include #include "../library/mylib.h" #include "project.h" int main() { rect('-',75,4); data(); rect('+',75,3); }
Здесь два раза вызывается библиотечная функция rect() и один раз функция data() из другого файла проекта. Чтобы сообщить функции main() прототип data() также подключается заголовочный файл проекта.
Файл project.h содержит всего одну строчку:
void data(void);
Из обоих файлов проекта с исходным кодом надо получить объектные файлы для объединения их потом с файлом библиотеки. Сначала мы получим исполняемый файл, содержащий статическую библиотеку, потом — связанный с динамической библиотекой. Однако с какой бы библиотекой мы не компоновали объектные файлы проекта, компилируются они как для статической, так и динамической библиотеки одинаково:
gcc -c *.c
При этом не забудьте сделать каталог project текущим!
Компиляция проекта со статической библиотекой
Теперь в каталоге project есть два объектных файла: main.o и data.o. Их надо скомпилировать в исполняемый файл project, объединив со статической библиотекой libmy1.a. Делается это с помощью такой команды:
gcc -o project *.o -L../library -lmy1
Начало команды должно быть понятно: опция -o указывает на то, что компилируется исполняемый файл project из объектных файлов.
Помимо объектных файлов проекта в компиляции участвует и библиотека. Об этом свидетельствует вторая часть команды: -L../library -lmy1. Здесь опция -L указывает на адрес каталога, где находится библиотека, он и следует сразу за ней. После опции -l записывается имя библиотеки, при этом префикс lib и суффикс (неважно .a или .so) усекаются. Обратите внимание, что после данных опций пробел не ставится.
Опцию -L можно не указывать, если библиотека располагается в стандартных для данной системы каталогах для библиотек. Например, в GNU/Linux это /lib/, /urs/lib/ и др.
Запустив исполняемый файл project и выполнив программу, мы увидим на экране примерно следующее:

Посмотрим размер файла project:
pl@desk:~/c/project$ ls -l project -rwxr-xr-x 1 pl pl 8648 ноя 19 07:46 project
Его размер равен 8698 байт.
Компиляция проекта с динамической библиотекой
Теперь удалим исполняемый файл и получим его уже связанным с динамической библиотекой. Команда компиляции с динамической библиотекой выглядит так (одна команда разбита на две строки с помощью обратного слэша и перехода на новую строку):
gcc -o project *.o \ > -L../library -lmy2 -Wl,-rpath. /library/
Здесь в отличии от команды компиляции со статической библиотеки добавлены опции для линковщика: -Wl,-rpath. /library/. -Wl — это обращение к линковщику, -rpath — опция линковщика, ../library/ — значение опции. Получается, что в команде мы два раза указываем местоположение библиотеки: один раз с опцией -L, а второй раз с опцией -rpath. Видимо для того, чтобы понять, почему так следует делать, потребуется более основательно изучить процесс компиляции и компоновки программ на языке C.
Следует заметить, что если вы скомпилируете программу, используя приведенную команду, то исполняемый файл будет запускаться из командной строки только в том случае, если текущий каталог project. Стоит сменить каталог, будет возникать ошибка из-за того, что динамическая библиотека не будет найдена. Но если скомпилировать программу так:
gcc -o project *.o -L../library -lmy2 \ > -Wl,-rpath,/home/pl/c/library
, т.е. указать для линковщика абсолютный адрес, то программа в данной системе будет запускаться из любого каталога.
Размер исполняемого файла проекта, связанного с динамической библиотекой, получился равным 8544 байта. Это немного меньше, чем при компиляции проекта со статической библиотекой. Если посмотреть на размеры библиотек:
pl@desk:~/c/library$ ls -l libmy* -rw-r--r-- 1 pl pl 3712 ноя 19 07:35 libmy1.a -rwxr-xr-x 1 pl pl 7896 ноя 19 07:36 libmy2.so
, то видно, что динамическая больше статической, хотя исполняемый файл проекта со статической библиотекой больше. Это доказывает, что в исполняемом файле, связанном с динамической библиотекой, присутствует лишь ссылка на нее.
Курс с решением части задач:
pdf-версия
Как собрать библиотеку c из исходников
Предлагаю направить холивар, происходящий сейчас в параллельной теме, на более полезную тему.
Расскажите, как у вас организовано все касаемо исходников и компиляции. Какие, на ваш взгляд подходы устарели, что более удобно, а что не очень хорошо.
Мои соображения далее по тексту. Прошу учесть, что я работаю один, поэтому для командной разработки это может не подойти.
Для программ на С/С++ существует классический подход:
Алгоритмический код помещается в файлы .c или .cpp.
Определения классов, функций, глобальных переменных кладутся в .h
и закрываются #ifndef KAKAJATOFIGNJA
Про этот классический подход хорошо писал сам Страуструп в его книге по C++.
Приведены доводы и полезности такого подхода. Но сейчас, ИМХО, возникают более удобные альтернативы, какие можно использовать вместе с классическим подходом.
Заградительные #ifndef сейчас не очень нужны, поскольку есть #pragma once
Лично я их не пишу. #pragma once имеется в MSVC, GCC и Clang, а другое мне не нужно.
Далее, всвязи с развитием шаблонного программирования все больше и больше исходников сейчас наблюдаю только в хидерах.
И я заметил, что сам предпочитаю писать так, даже не для шаблонов. Да и удобно как-то иметь один файл для одной сущности.
Очень просто и красиво:
#pragma once struct A < A() < . >void f1() < . >void f2() < . >>;
Не надо прыгать по файлам, все в одном месте.
Касаемо скорости компиляции всего этого, обычно проблем не возникает. Ниже по тексту будет о том, что делаю, если скорости не хватает.
Проблем перекрестных ссылок у меня почти не бывает, так что держать почти все в .hpp файлах для меня удобно.
И я не всегда держу все там, иногда использую отдельные .cpp.
Предпочитаю мелкие классы с разделением полномочий и принципом «одна сущность выполняет одну простую задачу».
Также развожу зависимости между классами, предпочитая подход «если не знаю что делать, пусть этим занимается вызывающий меня код,
а я делаю только то что в моей компетентности». Получается простая древовидная система.
Глобальные переменные я почти не использую. Говорю почти, потому что использую API и библиотеки, в которых без них не обойтись.
Если возникает надобность, то не использую конструирование объекта, предпочитая POD структуры с минимальной обвязкой.
Так что все это хорошо ложится в схему «несколько .cpp и большая куча .hpp»
Далее по файловой системе.
GCC и MSVC из IDE кидают весь мусор компиляции немного по-разному. (Про XCode ничего сказать не могу, т.к. не использую.) GCC мусорит прямо рядом с исходником,
MSVC создает подкаталоги и все кидает туда. Это вызывало определенные неудобства при тестировании и прототипировании, поскольку текущая директория при этом находится не рядом с exe.
Плохо и там и там, я сделал иначе, благодаря build системе.
Мой выбор пал на ninja build. Были альтернативы: Makefile, CMake и другие. Ninja build привлек простотой и изящностью своего языка.
Конечно, для каждого компилятора пришлось ручками писать все с нуля, но зато теперь я уверен, что все сделано оптимально, ведь у меня есть полный контроль над файлами и ключами компиляции.
И да, я поддерживаю GCC, MSVC, CUDA Nvcc, Spir и кучу мелкотни, в т.ч. и самописной.
Внутри использую пути в unix-стиле /dir/dir — ninja и Windows компиляторы все это поддерживают. Единственно, пришлось для Windows использовать юниксовские тулзы типа cp.
Ранее я придерживался такой схемы директорий, близкой к unix-like:
Project/ bin/ сюда кидаем скомпилированные бинарники inc/ сюда кидаем сторонние исходники, библиотеки и т.п. src/ здесь только исходники temp/x64-debug/ сюда помещается весь мусор и потом легко удаляется одной командой rm build-mac/ здесь проекты для компиляции, скрипты и т.п. build-win/ .
Получалось красиво, но доставала необходимость постоянно прыгать по директориям.
В конце концов я плюнул на такой формализм и упростил:
Project/ исходики и почти все тут inc/ сюда кидаем сторонние исходники, библиотеки и т.п. temp-x64-debug/ сюда помещается весь мусор и потом легко удаляется.
Если что-надо специфическое, например, инсталлятор, то создаю поддиректорию. Именование директорий более свободное, в зависимости от проекта.
Стало чуть более громоздко для глаз, но в целом более удобно для работы.
Про скорость компиляции. Сторонние библиотеки, в зависимости от настроения, либо компилирую в lib, либо включаю .cpp в свой проект.
Все зависит от скорости их компиляции. Некоторые библиотеки компилируются по несколько десятков секунд, так что чтобы не ждать, их собираю в lib.
Поскольку у меня лично свои проекты небольшие, от силы до сотен килобайт суммарно, проблем со скоростью компиляции пока нет, если что,
буду оптимизировать — перемещать методы в .cpp файлы, делить на библиотеки и т.п.
Precompiled headers я не использую по-ненадобности. Возни с ними и возникающих периодически проблем версионности много, а выигрыш в итоге небольшой.
Раньше возился, теперь забросил это дело.
Автоматизация.
Для Windows использую .bat файлы, для Linux и Mac OS .sh
Этого хватает. Если очень надо, могу свою программу написать, но обычно средств скриптов хватает.
Разработка в целом.
У меня на разных дисках в разные разделы на разных компьютерах поставлена куча разных операционных систем.
Перегружаюсь и работаю там. Надо потестить в другой системе — перегружаюсь и снова работаю там.
(Кстати, посоветуйте удобные и простые редакторы для Linux GUI и MacOS. Удобства Windows мне не хватает на Linux и маке.)
Есть несколько разных машин с разным железом. Удобно для отлова специфических ситуаций.
Возможно, все можно было упростить, если использовать виртуальные машины, но я работаю с GPU, поэтому нужен доступ к железу.
Основной код пишется под Windows из-за удобства и богатства всего для работы. Под Linux предпочитаю CentOS. Минималистично и совместимо, поскольку в него ставится все старье.
Исходники держу в разделе с файловой системой exFAT. Его понимает и Mac и Linux. Также не надо заботиться о правах, поскольку по-умолчанию получается 0777.
Тестирование.
Разработкой через тестирование я пытался заниматься, но все равно скатился в традиционный подход — сначала код а потом его тестирование.
Единственно, я научился правильно тестировать код, так что у меня почти нет надобности в трассировке программ и визуальной отладки.
Если надо что-то проверить — максимум логгирование.
А так достаточно простых тестов if (получилось != нужное) сообщаем_о_фигне.
Это стало экономить огромное количество времени на возню мышкой, подсвечивание переменных и прочий ужас из методов отладки 90х годов прошлого века.
Поэтому GUI мне не нужно.
Сильных изменений исходников, чтобы ничего не поломалось, у меня почти не бывает, так что покрытие тестами для надежности не использую.
Абсольное число всех багов, какие я выловил за все годы работы — это работа логики GUI плюс алгоритмические специфические баги из-за разницы окружений запуска.
Так что unit тестирование в моем случае — лишняя нагрузка на меня.
Если бы работал в команде из разношерстных программистов с разным опытом, то наверняка выбрал бы unit тестирование основной парадигмой команды.
Всвязи с подходом к тестирование через написание самого кода тестирования отпала надобность делать отдельные билды Release и Debug.
Что упрощает всю обвязку скриптов и build. У меня все теперь Release. Если очень надо, можно немного изменить ключи компиляции и проверить работу программы
с использованием отлова выхода за пределы массивов и т.п. И при необходимости могу запустить отладку в QtCreator.
Прототипирование.
Копирую шаблонный проект, там что-то делаю, проверяю работоспосность. Очень быстро. Не надо ничего настраивать, т.к. шаблонный проект уже настроен.
Когда прототипы показывают то что мне надо, переписываю начисто в рабочий проект. Почти всегда приходится переписывать, поскольку специфика работы предполагает
большую часть моей работы как исследовательскую и поисковую (R&D), так что заранее я не знаю, как нужно сделать оптимально сразу. Да и многое потом выкидывается как ненужное.
Даже многолетний опыт не позволяет сразу писать хорошо. Приходится выкидывать лишнее, оптимизировать систему классов, переименовывать. В общем, у меня всегда
используется рефакторинг, прототип в рабочий проект не кидаю. Хотя каюсь, большую часть моей программистской деятельности я писал по-другому, пытаясь сразу сделать хорошо, но
в итоге хорошо не выходило. Двойная разработка через прототипирование избавляет от этой проблемы. Да, чуть медленней, но цена этого окупится при поддержке и развитии версий.
Система версий.
Для прототипов не использую. А зачем, когда работа на это от силы на день-два. Редко когда на неделю. Если что-то надо сохранить, по-старинке создаю копию прототипа и там меняю.
Для готовых проектов, которые живут долго и развиваются, использую Git. Никаких GUI не использую, т.к. и вручную все удобно. Если что, можно написать командный скрипт.
В-общем-то все, какие-то мелочи я не стал писать. Да и это лишь затравка для холиварщиков.
Установка библиотек C, C++ прямо в проект
Есть ли готовые решения в виде менеджера пакетов, желательно source-based, который бы ставил все нужные зависимости не в систему, а в папку проекта?
Желательно чтобы это было кроссдистрибутивно (но интересуют и иные варианты, если нельзя так).
То есть — менеджер должен из некоего репозитория ставить исходники библиотеки. Бинарники — дело десятое, в принципе они в данном подходе не нужны, потому что все равно будут собраны не под целевую систему.
Вроде простая задача, и во всяких Node, Python решается штатно, а такой затык. Или я в танке еду и не знаю про очевидные решения. Помогите, кто знает?

James_Holden ★★★
03.08.21 12:53:05 MSK
← 1 2 3 4 5 →
Знаю conan и vcpkg.
fernandos ★★★
( 03.08.21 12:55:26 MSK )
Просто добавляю всё нужное через git submodule, если у проекта есть официальный общедоступный git. Если нет, то приходится просто кидать исходники в подкаталог.
KivApple ★★★★★
( 03.08.21 12:56:39 MSK )
Ответ на: комментарий от KivApple 03.08.21 12:56:39 MSK

В принципе это неплохо. Но хотелось бы еще искать и просто командой install ставить. Как с обычным пакетным менеджером.
James_Holden ★★★
( 03.08.21 12:57:56 MSK ) автор топика
Ответ на: комментарий от fernandos 03.08.21 12:55:26 MSK

Какой-то чисто виндузятнический опрос. Меня интересует это исключительно в линуксе пока.
Это похоже на то что надо. Только я не пойму, а какие бинарники он ставит? Для какого дистрибутива собранные?
James_Holden ★★★
( 03.08.21 13:01:19 MSK ) автор топика
Ответ на: комментарий от James_Holden 03.08.21 13:01:19 MSK
ЕМНИП, он определяет вашу ОС, компилятор, а потом пытается подтянуть этот пакет, если не выйдет — он соберёт.
fernandos ★★★
( 03.08.21 13:04:41 MSK )
Последнее исправление: fernandos 03.08.21 13:04:49 MSK (всего исправлений: 1)

Универсальной таблетки нет. Для небольших проектов неплох cget + direnv с настройкой вида
export CGET_PREFIX=`pwd`/cget
AlexVR ★★★★★
( 03.08.21 13:07:26 MSK )
Ответ на: комментарий от fernandos 03.08.21 13:04:41 MSK

Вроде есть ключ –build который принудительно заставляет все собирать.
Отлично, пока это ровно то что нужно.
James_Holden ★★★
( 03.08.21 13:07:54 MSK ) автор топика
Ответ на: комментарий от AlexVR 03.08.21 13:07:26 MSK

Я так понял, оно не из репозитория ставит, а надо вручную подсовывать ссылку?
James_Holden ★★★
( 03.08.21 13:09:52 MSK ) автор топика
Ответ на: комментарий от fernandos 03.08.21 13:04:41 MSK

Я и правда в танке ехал.
Все, проблема решена conan. Можно даже qt втыкать (но не нужно).
James_Holden ★★★
( 03.08.21 13:17:50 MSK ) автор топика
Ответ на: комментарий от James_Holden 03.08.21 13:09:52 MSK

Да. Но решает проблему добавления не стандартных пакетов .
AlexVR ★★★★★
( 03.08.21 13:40:04 MSK )
Ответ на: комментарий от James_Holden 03.08.21 12:57:56 MSK

можно написать скрипт для обычного пакетного менеджера (apt + dpkg), который будет распаковывать пакеты исходного кода в указанную директорию.
aiqu6Ait ★★★★
( 03.08.21 13:46:50 MSK )
Не люблю когда так делают, проект раздуваться быстро начинает. Все языки в которых так сделали начинают по мелочи всирать десятки гигабайт места в build tree. ALVR (поделие на rust) у меня всрало аж 8 гигов, хотя там нет ничего чему можно занимать много места. про то как node_modules растёт и так все в курсе.
Есть такая функциональность в meson
Ну и есть https://conan.io/
mittorn ★★★★★
( 03.08.21 13:50:31 MSK )
Ответ на: комментарий от aiqu6Ait 03.08.21 13:46:50 MSK

Вот как раз нужно на системе без стандартного пакетного менеджера.
James_Holden ★★★
( 03.08.21 13:50:48 MSK ) автор топика
Ответ на: комментарий от mittorn 03.08.21 13:50:31 MSK

Все языки в которых так сделали начинают по мелочи всирать десятки гигабайт места в build tree
Это лучше, чем то же самое в систему.
conan уже заценил.
James_Holden ★★★
( 03.08.21 13:52:36 MSK ) автор топика
Ответ на: комментарий от AlexVR 03.08.21 13:07:26 MSK
Вот и для cmake значит тоже такое есть
mittorn ★★★★★
( 03.08.21 13:53:01 MSK )
Ответ на: комментарий от James_Holden 03.08.21 13:52:36 MSK
Но лучше сабмодулями подцепить нужные версии и интегрировать в систему сборки, так не будет соблазна «СЕЙЧАС Я БУДУ УСТАНАВЛИВАТЬ ВСЕ БИБЛИОТЕКИ»
mittorn ★★★★★
( 03.08.21 13:55:41 MSK )
Ответ на: комментарий от James_Holden 03.08.21 13:50:48 MSK

Тогда, как выше рекомендовали, подмодули — идеальное решение. Тебе все равно нужен git, подмодули можно обновлять автоматически или по необходимости. Ставить — 3-4 строки в файл прописать.
aiqu6Ait ★★★★
( 03.08.21 14:00:54 MSK )
Ответ на: комментарий от mittorn 03.08.21 13:55:41 MSK

Дело в том, что потом деплой предполагает другой путь сборки зависимостей. То есть они должны быть как-бы не внутри исходников проекта, а внутри папки в которую идет сборка (либо сбоку). Не полностью интегрироваться в проект. Насколько я понял с conan как раз этого и можно добиться.
James_Holden ★★★
( 03.08.21 14:01:35 MSK ) автор топика
Ответ на: комментарий от aiqu6Ait 03.08.21 14:00:54 MSK

Тогда, как выше рекомендовали, подмодули — идеальное решение
Не совсем. Мне надо чтобы исходники проекта не содержали интегрированных зависимостей. Просто чтобы они для сборки ставились не в систему, а где-то рядом с проектом. Или внутри, но не прямо интегрировались во все исходники.
James_Holden ★★★
( 03.08.21 14:03:20 MSK ) автор топика
Последнее исправление: James_Holden 03.08.21 14:03:40 MSK (всего исправлений: 1)
Harald ★★★★★
( 03.08.21 14:19:26 MSK )
Ответ на: комментарий от James_Holden 03.08.21 14:01:35 MSK
cget скорее всего тоже, так что смотри эти 2 варианта. Но я конечно считаю интеграцию в проект предпочтительнее
mittorn ★★★★★
( 03.08.21 14:30:15 MSK )

hateyoufeel ★★★★★
( 03.08.21 14:31:01 MSK )
Ответ на: комментарий от Harald 03.08.21 14:19:26 MSK

Ты не юниксоид. Задумайся — если по канонам юникс-вея «утилита должна делать одну задачу и делать хорошо», то почему ты используешь утилиту «пакетный менеджер» которая делает сразу несколько задач:
- Установка/удаление/обновление пользовательских приложений
- Установка/удаление/обновление конфигов
- Установка/удаление/обновление системных служб
- Установка/удаление/обновление библиотек для разработки, причем для всех языков сразу!
Это дикое нарушение принципов юникс-вея. Мало того что делается сразу много задач, так еще и все они делаются плохо! А юникс-вей требует делать хорошо.
Я пытаюсь решить эту проблему, отделив хотя бы управление библиотеками для разработки от управления приложениями и остальными системными компонентами.
А если у тебя это вызывает такую реакцию, причины тут может быть две — 1) ты не понимаешь что такое юникс-вей 2) ты противник юникс-вея. А с большой вероятностью и то, и другое.
James_Holden ★★★
( 03.08.21 14:32:32 MSK ) автор топика
Ответ на: комментарий от hateyoufeel 03.08.21 14:31:01 MSK

Насколько я понимаю, Nix создаст некое подобие контейнера, в котором я могу при помощи Nix поставить все зависимости и вести разработку? Или не так?
Смущает во-первых оверкилл — сложность самого инструмента Nix по сравнению с такой простой задачей, и во-вторых — насколько этот контейнер изолируется от внешнего мира?
James_Holden ★★★
( 03.08.21 14:34:45 MSK ) автор топика
Ответ на: комментарий от James_Holden 03.08.21 14:32:32 MSK
Пакетный менеджер не делает всё вышеперечисленное одним бинарником самостоятельно, он дёргает кучу разных утилит для этого, которые делают хорошо одну задачу.
Harald ★★★★★
( 03.08.21 14:34:55 MSK )
Посмотри на nix, там есть сторадж, зависимости как таковые туда кладутся, но на систему это никак не влияет. Запускаешь shell в котором все нужные зависимости уже есть. Я сделал себе репозиторий, там для всех моих проектов описание, релиз — обновление в этом репозитории. Очень удобно.
Вот статья, мне такой способ немного не подходит, но как введение норм https://habr.com/ru/post/281611/
Для меня важно чтобы менеджер пакетов был один для всего, а не для плюсов только например. У меня некоторые проекты питоновские либы используют, фронт есть и т.д. Вот никс как раз такой. Это не менеджер пакетов, а менеджер окружения. Если кто то захочет присоединиться к проекту моему, то ему такое же как у меня окружение собрать — две минуты.
zerhud ★
( 03.08.21 14:36:39 MSK )
Ответ на: комментарий от Harald 03.08.21 14:34:55 MSK

Нет, именно делает одним бинарником. У тебя что, блин, deb пакет с либрой и deb пакет с fftw3-dev ставит разный dpkg? Вот это новости.
Ты вообще представляешь как пакетный менеджер работает?
James_Holden ★★★
( 03.08.21 14:37:41 MSK ) автор топика
Ответ на: комментарий от zerhud 03.08.21 14:36:39 MSK

Запускаешь shell в котором все нужные зависимости уже есть
Вот это и пугает. Мне не нужен шелл, мне нужна IDE которая все видит, и она за пределами «контейнера» и работает в своем отдельном контейнере, где возможности обрезаны.
Для меня важно чтобы менеджер пакетов был один для всего
А для меня — наоборот.
Это не менеджер пакетов, а менеджер окружения.
Ну понятно. Мне нужен просто, и тупо — менеджер библиотек. Даже не назову это пакетами.
James_Holden ★★★
( 03.08.21 14:40:47 MSK ) автор топика
Ответ на: комментарий от James_Holden 03.08.21 14:37:41 MSK
Нет, именно делает одним бинарником. У тебя что, блин, deb пакет с либрой и deb пакет с fftw3-dev ставит разный dpkg? Вот это новости.
dpkg занимается непосредственно установкой пакета, это уже как бы маленькая подзадача
Harald ★★★★★
( 03.08.21 14:45:24 MSK )
Ответ на: комментарий от James_Holden 03.08.21 14:40:47 MSK
Я юзаю qtcreator, его из нужного окружения запускаешь и все работает. Так в системе даже компилятор не стоит. Ещё visual code работает. Ну частенько тупо в виме сижу.
Я пытался раньше так сделать, чтобы проекты в папке лежали, потом понял что тупиковый путь. У меня проекты множились, выделял библиотеки, переиспользовал их в нескольких проектах. Очень трудно было для каждого подпапку так сделать, не все либы ложатся в такую схему (по началу ок, потом расширяешь проект и облом). Пришёл потом что легче сделать репозиторий deb пакетов. Написал пару скриптов и все дела (ну они проходили по всем нужным дирам, обновляли версии в репе, потом устанавливали новые версии). Такое и для контейнера ок.
Но проще и функциональнее никса ничего не нашёл.
zerhud ★
( 03.08.21 14:50:09 MSK )
Ответ на: комментарий от Harald 03.08.21 14:45:24 MSK

Дело же не в dpkg как таковом. Есть deb пакет, и в нем может быть вот все это вышеперечисленное. То есть один и тот же пакет для всего.
А если разобраться, то задача управления библиотеками для разработчика и задача установки приложений для пользователя — это весьма разные вещи. Разные люди, с разными знаниями, с разными целями. А эти две задачи соединили одним инструментом, который ставит deb пакет.
Опять получается проблема, что тут надо за деревьями видеть лес. Ты посмотри не на частности, кто там архив распаковывает, кто копирует и т. д. Речь не о таких задачах. А о задачах со стороны человека.
Человеку надо 1) установить приложение 2) установить библиотеку (не как зависимость для приложения из репозитория, а для разработки, с h файлами и исходниками).
Это две совсем разные, не связанные задачи. Разные требования. Для каждой должен быть отдельный инструмент.
James_Holden ★★★
( 03.08.21 14:50:28 MSK ) автор топика
Ответ на: комментарий от James_Holden 03.08.21 14:50:28 MSK
то задача управления библиотеками для разработчика и задача установки приложений для пользователя — это весьма разные вещи.
и там файлы распаковываются, и здесь файлы — в чём разница?
Harald ★★★★★
( 03.08.21 14:54:42 MSK )
Ответ на: комментарий от zerhud 03.08.21 14:50:09 MSK

потом расширяешь проект и облом
А можно пример такого облома?
James_Holden ★★★
( 03.08.21 14:57:35 MSK ) автор топика
Ответ на: комментарий от Harald 03.08.21 14:54:42 MSK

и там файлы распаковываются, и здесь файлы — в чём разница?
То есть по твоему у человека когда он сел за компьютер задача — распаковать файлы? Ты даже не понимаешь что в такой постановке вопроса не так?
Поясню — человек плевал на файлы и на распаковку. У него есть задачи, человеческие. Что-то сделать на компе. Распаковать файлы — это не цель человека, это операция при помощи которой машина решает более общую, иную, глобальную задачу человека.
Теперь попробуй посмотреть на все это с точки зрения задачи человека, а не машины.
James_Holden ★★★
( 03.08.21 15:01:46 MSK ) автор топика
Ответ на: комментарий от James_Holden 03.08.21 15:01:46 MSK
давай теперь отдельный пакетный менеджер для десктопных обоев, отдельный для шревтов, отдельный для таймзон пилить, разные же задачи везде
Harald ★★★★★
( 03.08.21 15:11:23 MSK )
Ответ на: комментарий от James_Holden 03.08.21 15:01:46 MSK
У него есть задачи, человеческие. Что-то сделать на компе.
Но они все сводятся к скачиванию и распаковке файлов пакетным менеджером
Harald ★★★★★
( 03.08.21 15:13:03 MSK )
ну в принципе Portage из генты именно это всё и делает, и можно его натравить на другую директорию в хомяке, отличную от корня
Harald ★★★★★
( 03.08.21 15:16:02 MSK )
Harald ★★★★★
( 03.08.21 15:17:11 MSK )
Ответ на: комментарий от Harald 03.08.21 15:13:03 MSK

Но они все сводятся к скачиванию и распаковке файлов пакетным менеджером
Не сводятся. Пакетный менеджер должен скачивать и распаковывать совершенно по разному. А возможно и не скачивать. И не распаковывать. В зависимости от задачи.
давай теперь отдельный пакетный менеджер для десктопных обоев, отдельный для шревтов, отдельный для таймзон пилить, разные же задачи везде
Ты не можешь выделять и ставить задачи, объединять сходные задачи, разделять не сходные, отсюда твои проблемы — поэтому ты ничего не можешь понять.
Таймзоны и обои это действительно разное, но и то, и другое — часть более общих задач. То есть у тебя должны быть разные менеджеры для таймзон и для обоев, но это не будут менеджеры только лишь для таймзон и только лишь для обоев.
Кстати уже давно обои и таймзоны управляются в линуксе разными менеджерами. Например в KDE обои и темы оформления ставятся отдельным менеджером специально для этого.
James_Holden ★★★
( 03.08.21 15:19:00 MSK ) автор топика
Ответ на: комментарий от Harald 03.08.21 15:16:02 MSK

ну в принципе Portage из генты именно это всё и делает, и можно его натравить на другую директорию в хомяке, отличную от корня
Это была первая мысль, я и раньше о таком применении portage слышал. Возможно, это и будет решение типа conan.
James_Holden ★★★
( 03.08.21 15:21:23 MSK ) автор топика
Ответ на: комментарий от James_Holden 03.08.21 15:19:00 MSK
Ты не можешь выделять и ставить задачи, объединять сходные задачи, разделять не сходные, отсюда твои проблемы — поэтому ты ничего не можешь понять.
Либо это ты видишь разные задачи, где на самом деле задача одна. Нужно умение обобщать 🙂
Harald ★★★★★
( 03.08.21 15:23:50 MSK )
Ответ на: комментарий от James_Holden 03.08.21 14:57:35 MSK
Первое что в голову пришло: сделал для своего проекта веб морду, настроить демона. Хочется чтобы поинтереснее было, а для этого всякие либы фронтовые нужны, плюс статика. Когда разрабатываешь хочется запустить это все прям из директории сборки за один клик, а не деплоить пол часа чтобы посмотреть на новую фичу, а для этого нужно статику положить и запустить сервис. Тесты интеграционные запустить. Гитом можно подпроекты сделать, там будут файлы, приходиться писать скрипты чтобы их от туда доставать и класть куда надо. Потом поизменчешь пару раз, это все становиться очень запутанным.
Вот ещё пример: сервис на плюсах, и понадобилось запускать на питоне скрипты, вкорячить не проблема питон, но потом например либу питоновскую нужно как то подключить, собрать для него что нибудь..
Или вот, я написал свой кодогенератор, это исполняемый файл. Пока там питон нужен (времени нет выпилить это). Вот как его как подпроект оформить? Он в куче микросервисов используется а собирать долго. Плюс я там юзаю последние плюсы, а не все проекты еще перевёл на них, то есть компилятор разный нужен (ну и как сейчас не знаю, а пол года назад шлангом я не мог собрать генератор, а либу хотел именно шлангом дев версию, там кавка больше нравиться).
Ещё бесит момент: написал либу, используешь ее в трёх проектах например. Потом обновил что нибудь. Надо потом что, по всем проектам идти и руками обновлять? А от тех трёх зависит ещё по два от каждого.. вот именно с такой проблемой столкнулся пару недель назад, там поразвесистее схема была. Нет единого места где решаются такие проблемы (когда на никс перешёл тоже не сразу догадался как сделать там, чтобы это в пару строк решалось).
zerhud ★
( 03.08.21 15:30:18 MSK )
Ответ на: комментарий от Harald 03.08.21 15:23:50 MSK

Вот простой пример твоей логики.
У боксера и кузнеца задачи сводятся к одному — надо бить.
Почему тогда боксер не бьет противнику в табло молотом? Задача, по твоей логике одна.
Потому что надо бить по-разному, разный объект по которому бьют, разная цель, которой пытаются достичь ударом.
Поэтому разные инструменты — боксерская перчатка и молот. А ты предлагаешь найти что-то среднее, чем можно было бы и ковать и бить в торец человеку без цели его покалечить. В итоге ты и ковать нормально не сможешь, и людей калечить будешь на право и на лево.
Что мы и наблюдаем в линуксе. Пользовательские приложения при помощи deb «ковать» фигово — очень неудобно. И людей калечит — повреждает мышление deb религией.
James_Holden ★★★
( 03.08.21 15:41:40 MSK ) автор топика
Ответ на: комментарий от zerhud 03.08.21 15:30:18 MSK

Так в принципе, поэтому я и хочу использовать именно менеджер, а не интегрировать вручную все либы в каждый проект.
Если общая либа, то надо ее собрать пакетом под этот менеджер, и дальше можно будет из репозитория везде обновить, в том числе автоматически. С любым менеджером пакетов можно. Что ты и делаешь с Nix, если я правильно понял.
А чем тут Nix предпочтительнее чем например conan я пока так и не понял.
James_Holden ★★★
( 03.08.21 15:47:25 MSK ) автор топика
Ответ на: комментарий от James_Holden 03.08.21 15:41:40 MSK
Задача в твоих примерах сводится к передаче кинетической энергии, т.е. распаковке файлов 🙂
Harald ★★★★★
( 03.08.21 15:55:09 MSK )
Ответ на: комментарий от Harald 03.08.21 15:23:50 MSK

Более того, что если у тебя задача — распаковать deb как архив, то она решается архиватором ar, а dpkg это нарушение принципа KISS.
То есть нельзя сказать что задача пакетного менеджера сводится к распаковке архивов. Тогда вопрос, а почему это не делает архиватор.
James_Holden ★★★
( 03.08.21 15:55:33 MSK ) автор топика
Ответ на: комментарий от James_Holden 03.08.21 15:41:40 MSK
Пользовательские приложения при помощи deb «ковать» фигово — очень неудобно.
мне удобно, миллионам пользователей дебиана и производных тоже удобно, это ты какой-то особенный
Harald ★★★★★
( 03.08.21 15:56:11 MSK )

Я только про conan слышал. А для эмбедов юзаю platformio.
Собсна, это вечная боль, из-за которой я хотел бы свалить на раст. Но его под эмбеды так и не прокачали для нубов (так чтобы в один клик ставился не только компилятор, но и программатор и т.п.)
Vit ★★★★★
( 03.08.21 15:57:06 MSK )
Ответ на: комментарий от James_Holden 03.08.21 15:55:33 MSK
Более того, что если у тебя задача — распаковать deb как архив, то она решается архиватором ar, а dpkg это нарушение принципа KISS.
а почему ты вдруг решил, что архиватор не задействован и dpkg не вызывает tar для распаковки? tar вполне себе в зависимостях у dpkg указан
Harald ★★★★★
( 03.08.21 15:58:05 MSK )
Ответ на: комментарий от Harald 03.08.21 15:56:11 MSK

На миллиарда пользователей винды — пользователи дебиана это и есть особенные мазохисты. Это вообще не аргумент. Оглянись вокруг — никто не знает что это за Дебиан. Ты не можешь это преподносить как норму.
Задача в твоих примерах сводится к передаче кинетической энергии, т.е. распаковке файлов 🙂
Почему боксер и кузнец ее разными инструментами решает?