Используем код из 6 части Создание собственной библиотеки. Компилируем библиотеку, затем компилируем клиент для работы с ней.
Но на этот раз выполнять операции сборки будет утилита make, в которой мы пропишем необходимые команды.
Make позволяет автоматизировать процесс сборки, где мы работаем с командами (targets), которые сами укажем.
Таким образом, вместо того, чтобы постоянно вручную писать команды сборки вроде:
gcc my_file.c -lxxx ....Это будет делать за нас Make, и все ограничится простым вызовом, в месте, где находится файл Makefile:
make- Makefile сборки библиотеки
custom_logger. - Makefile сборки клиента
client_custom_logger.
public/code_sources/linux-c-system-programming-essentials/7-makefile/custom_logger/Makefile
Ссылка
public/code_sources/linux-c-system-programming-essentials/7-makefile/client_custom_logger/Makefile
Ссылка
Создается файл Makefile внутри папки с проектом - custom_logger:
custom_logger это библиотека, которая будет использоваться программой client_custom_logger, поэтому Makefile для нее заточен под сборку именно библиотеки.
Основная особенность make это поддержка переменных, мы можем в начале файла указать наши переменные, которые затем будут заменять своим содержимым те места, где они используются.
Объявление переменной идет так:
VARIABLE := value
Обращение затем к этой переменной, с целью получить ее значение делается так:
$(VARIABLE)
Затем из этих переменных складываются команды (targets).
Разберем поэтапно каждую переменную:
CC- указываем компилятор, который будет использоваться, в нашем случае этоgccCC := gcc
CFLAGS- флаги компилятора, для конфигурации процесса компиляцииCFLAGS := -O2 -Wall -Wextra -pedantic -fPIC
-O2- оптимизация на уровне 2.-Wall- выводим все предупреждения, если они появятся.-Wextra- выводим дополнительные предупреждения, если они появятся.-pedantic- более строгий анализ кода.-fPIC- генерация позиционно-независимого кода, важно для сборки библиотек.
SRCS- файлы исходного кода проектаSRCS := $(wildcard src/*.c)Ищутся все файлы с расширением
.cв папкеsrcи подставляются в эту переменную.
BINиLIBпути
Просто названия папок , где будут лежать результаты сборок.BIN := bin LIB := lib
NAME- имя выходного файлаNAME := customlogger
LIB_PATH- итоговый путь где будет лежать библиотека.soLIB_PATH := $(PWD)/$(LIB)Обратите внимание, что путь будет такой: рабочая директория процесса оболочки
PWD(т.е. откуда запускаетсяmake) +lib.
OBJS- имена объектных файловOBJS := $(SRCS:src/%.c=$(BIN)/%.o)Здесь просто идет копирование имен исходных файлов с форматом
.cна формат.o. Это просто имена, так как на каждый файл исходного кода будет свой объектный файл (1 к 1) , например,src/custom_logger.cстанетbin/custom_logger.oи так далее.
Теперь объявим цели сборки (targets)
all: build_shared
build_object:
$(CC) $(CFLAGS) -c $(SRCS) -o $(OBJS)
build_shared: build_object
$(CC) -shared -Wl,-soname,lib$(NAME).so -o $(LIB)/lib$(NAME).so $(OBJS)
setenv:
@echo 'export LD_LIBRARY_PATH="$(LIB_PATH):$$LD_LIBRARY_PATH"'
clean:
rm -r $(BIN)/* && rm -r $(LIB)/*
.PHONY: all build_object build_shared setenv clean
Пойдем по пути простого вызова из терминала команды
makeкоторая запустит дефолтный таргет.
default target в make
Это первый указанный таргет по списку, можно указать дефолтный таргет самому, задав специальную переменную:
.DEFAULT-GOAL := all
all- в нашем случае просто переправляет к таргетуbuild_shared.build_shared- сборка библиотеки. Сперва вызывает таргетbuild_object, и делает следующее, подставляя вместо переменных значения:
gcc -shared -Wl,-soname,libcustomlogger.so -o lib/libcustomlogger.so bin/custom_logger.obuild_object- сборка объектных файлов:
gcc -O2 -Wall -Wextra -pedantic -fPIC -c src/custom_logger.c -o bin/custom_logger.oИтого порядок операций такой:
build_objectbuild_shared
Сперва строим объектные файлы, а затем из них собираем библиотеку.
Важно
Копия библиотеки
libcustomlogger.so, собранная раньше, должна быть в папкеclient_custom_logger/lib/libcustomlogger.so!
Makefile выглядит просто, но есть интересные флаги для компоновщика:
OUT_NAME := client_custom_logger.out
LINKER_BUILD_TIME := -Llib -lcustomlogger
LINKER_RUNTIME_PARAMS := -Wl,-rpath,'$$ORIGIN/lib'
all:
$(CC) $(SRCS) $(LINKER_BUILD_TIME) $(LINKER_RUNTIME_PARAMS) -o $(OUT_NAME)
.PHONY: all
LINKER_BUILD_TIMEуказывает флаги для компоновщика, которые используются во время сборки.
-Llibуказывает на папку где размещена библиотека, в нашем случае это папка
lib.
-lcustomloggerуказывает на имя библиотеки, в этой папке. Обратим внимание что в имени файла
libcustomlogger.soне учитывается префиксlibи расширение.so, поэтому имя для компоновщика изlibcustomlogger.soпревращается вcustomlogger.
LINKER_RUNTIME_PARAMSпередает опции времени выполнения программы компоновщику
-Wl,<опции>Опция -
-rpath,'$$ORIGIN/lib'прописываетRUNPATHв исполняемомELFфайле. Эта опция используется для передачи пути библиотекам, которые нужны приложению В нашем случае это такой путь$$ORIGIN/lib.Переменная
$ORIGINэто путь директории, где будет находится исполняемый файл. Итого будет путь такой<путь_к_программе>\libВ директорииlibразмещена наша библиотекаlibcustomlogger.so.
Утилита make позволяет нам писать скрипты сборки в файлах Makefile, настраивать связи этапов сборок, гарантируя порядок. Возможность использования переменных упрощает написание скриптов сборки. Для сборки проекта большего чем вывод Hello World ! - это незаменимый инструмент.