pcpm - пакетный менеджер для C
Дело было вечером, делать было нечего, и я решил: а почему бы не сделать “пакетный” менеджер для C библиотек.
в
Cнет пакетов, потому что нет механизма пространств имён. Всё живёт в общем пространстве символов, так что корректнее говорить не о пакетах, а о менеджере библиотек.
Просто скачивать библиотеки - скучно. Поэтому пакет - это python-скрипт, который может сделать какую-то полезную (или не очень) фигню: сгенерировать код, подготовить обёртки, подтянуть бинарники, что угодно.
Оглавление
зачем?
Мне хотелось:
- управления зависимостями.
- минимизировать ручной установки флагов и путей.
- кодогенерация.
примеры
pjim
Пакет pjim генерирует 2 функции вида
pjim_<struct name>_<serialization/deserialization>
для структур, помеченных // @PJIM.
Используется библиотека tsoding/jim.
#include <stdio.h>
#include "jim.h"
#include "jimp.h"
#include "pjim.h"
// @PJIM
typedef struct
{
int number;
int number_arr_capacity;
int number_arr[10];
} some_struct;
int main(void){
Jim jim = {.pp=4};
some_struct ss = {.number=33, .number_arr_capacity=3};
for (size_t i = 0; i < ss.number_arr_capacity; i++)
ss.number_arr[i] = i;
// serialization
pjim_some_struct_serialization(&jim, &ss); // автоматически сгенерированная функция
printf("сериализованная структура JSON:\n");
fwrite(jim.sink, jim.sink_count, 1, stdout);
// deserialization
printf("\nдесериализованная структура:\n");
some_struct ds = {0};
Jimp jimp = {0};
jimp_begin(&jimp, "", jim.sink, jim.sink_count);
pjim_some_struct_deserialization(&jimp, &ds); // автоматически сгенерированная функция
printf("{\n\t\"number\": %d,\n\t\"number_arr_capacity\": %d,\n\t\"number_arr\": [\n", ds.number, ds.number_arr_capacity);
for (size_t i = 0; i < ds.number_arr_capacity; i++)
printf("\t\t%d,\n", ds.number_arr[i]);
printf("\t]\n}\n");
return 0;
}
./build/bin/main:
сериализованная структура JSON:
{
"number": 33,
"number_arr_capacity": 3,
"number_arr": [
0,
1,
2
]
}
десериализованная структура:
{
"number": 33,
"number_arr_capacity": 3,
"number_arr": [
0,
1,
2,
]
}
То есть ты просто помечаешь структуру, а пакет сам генерирует функции для сериализации/десериализации.
Для запуска примера:
pcpm initpcpm install pjim- ctrl+c, ctrl+v
pcpm build run
raylib-module
Пакет raylib-module - это попытка сделать что-то вроде «модулей».
Если попробовать слинковать в проекте две библиотеки, у которых есть хотя бы одна функция с одинаковым именем (или у тебя такая уже есть), то получаешь ошибку линковки. Сюрприз.
Вместо этого:
RaylibModule- структура с указателями на все функции.import_RaylibModule- загружаетdll/soи заполняет структуру.- В коде ты работаешь через
rl->FunctionName.
Конфликтов символов нет, потому что ничего не линкуется напрямую. Функции подтягиваются во время выполнения и хранятся в структуре с указателями, а не попадают в таблицу символов итогового бинарника. Минус: макросы, завязанные на функции, ломаются. Но их можно переписать под указатели.
Используется библиотека: raysan5/raylib
#include "raylib-module.h"
RaylibModule* rl;
int main(void){
rl = import_RaylibModule("./libraylib.so.5.5.0");
rl->InitWindow(800, 450, "raylib [core] example - basic window");
while (!rl->WindowShouldClose())
{
rl->BeginDrawing();
rl->ClearBackground(RAYWHITE);
rl->DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY);
rl->EndDrawing();
}
rl->CloseWindow();
return 0;
}
Для запуска:
pcpm initpcpm install raylib-module- ctrl+c, ctrl+v
pcpm build run
Установка
Зависимости:
- make
- python3
- pip
- git
Установка:
git clone https://github.com/ShadowCHuyna/pcpm --depth=1make install
Удаление: make uninstall
Создание проекта:
pcpm init- создание проектаpcpm build run- сборка и запуск.
команды
init Создать новый проект
install (i) Установить зависимости проекта
build (b) Собрать проект
run (r) Запустить проект
remove Удалить пакеты из проекта
set_template Создать или обновить шаблон config.json
Конфигурация проекта
{
"name": "example_name",
"target_name": "example_bin_name",
"mirrors": [
"http://pcpmirror.potatom.ru/packages",
"/example/path"
],
"origin": "./libs",
"compilation_args": ["-Wall", "-Wextra"],
"compiler": "gcc",
"linking_args": [],
"linker": "ld",
"workers": 4,
"assets": [],
"dependencies": {
"pjim": {}
}
}
name- имя проекта. Используется внутриpcpm, чисто идентификатор.target_name- имя итогового бинарника.mirrors- список источников пакетов. Можно указать HTTP-зеркало или локальную директорию.origin- куда устанавливаются библиотеки. (по умолчанию./)compilation_args- флаги компилятора (-Wall,-O2, и т.п.).compiler- какой компилятор использовать (gcc,clangи т.п.).linking_args- флаги линковки (-lm,-lpthreadи т.п.).linker- какой линковщик использовать.workers- количество потоков сборки.assets- директории с ресурсами (копируются в./build/bin).dependencies- зависимости проекта.
dependencies, assets, workers, linking_args, compiler, compilation_args, origin, mirrors - не обязательны.