Рис. 20.10. Страница свойств Librarian–General – Output File
Настройка свойств Librarian завершается нажатием клавиш «Применить» и «OK».
После осуществления всех настроек выполняются компиляция и сборка библиотеки. В процессе компиляции модули, входящие в состав библиотеки (файлы с расширением .c), сначала обрабатываются препроцессором языка C, затем компилируются независимо друг от друга. В результате получается набор файлов с расширением .obj, содержащих скомпилированный код библиотечных функций. Затем полученный набор объектных файлов (с расширением .obj) объединяется в библиотечный модуль (файл с расширением .lib).
Процесс сборки проекта статической библиотеки запускается из пункта меню Build Build containers. Результат выбора показан на рис.20.11.
371
Рис.20.11. Запуск компиляции и сборки библиотеки
Впроцессе сборки библиотеки компилятор и библиотекарь (Librarian) выводят в окно сообщений (Output) среды Visual Studio диагностическую информацию, содержащую результаты компиляции каждого из модулей, подключенных к проекту статической библиотеки, возможные предупреждения компилятора и конечную статистику (например, количество ошибок и предупреждений) сборки библиотеки (рис.20.12).
Врезультате произведенной компиляции получаем папку с именем созданной библиотеки (containers), где в папке Debug располагается двоичный объектный библиотечный модуль – файл с расширением .lib. Для данного слу-
чая это файл containers.lib.
Рис.20.12. Окно с сообщением об успешной компиляции библиотеки
Программные коды подключаемых файлов
// file stack.h
#ifndef STACK_H__ #define STACK_H__
/// by default a stack reserves space for 16 items #define STACK_INITIAL_CAPACITY 16
typedef struct stack {
///number of items in the stack int m_length;
///capacity of the stack
int m_capacity;
/// block of memory for the stack int *m_items;
} stack_t;
///create a new stack and returns it stack_t *stack_create (int capacity);
///destroys the stack and frees resources void stack_destroy (stack_t *stack);
///pushes an item into the stack
int stack_push (stack_t *stack, int item);
///pops the item from the stack int stack_pop (stack_t *stack);
///checks whether the stack is empty int stack_is_empty (stack_t *stack);
#endif
// file stack.c
#include <assert.h>
#include <malloc.h>
#include <stddef.h>
#include "stack.h"
static int stack_ensure_capacity (stack_t *stack, int capacity)
{
int capacityDesired; int *p;
if (stack->m_capacity >= capacity) return 1;
capacityDesired = stack->m_capacity * 2;
p = realloc (stack->m_items, capacityDesired * sizeof (int)); if (!p)
return 0;
stack->m_items = p; stack->m_capacity = capacityDesired; return 1;
}
stack_t* stack_create (int capacity) { stack_t *result;
if (capacity <= 0)
capacity = STACK_INITIAL_CAPACITY; result = malloc (sizeof (stack_t));
if (!result) return NULL;
result->m_items = malloc (capacity * sizeof (int)); if (!result->m_items) {
free (result); return NULL;
}
result->m_capacity = capacity;
result->m_length = 0; return result;
}
void stack_destroy (stack_t *stack)
{
assert (stack != NULL);
assert (stack->m_items != NULL);
free (stack->m_items); free (stack);
}
int stack_push (stack_t *stack, int item)
{
assert (stack != NULL);
assert (stack->m_capacity > 0); assert (stack->m_items != NULL);
if (!stack_ensure_capacity (stack, stack->m_length + 1)) return 0;
stack->m_items[stack->m_length++] = item; return 1;
}
int stack_pop (stack_t *stack)
{
assert (!stack_is_empty (stack));
return stack->m_items[--stack->m_length];
}
int stack_is_empty (stack_t *stack)
{
assert (stack != NULL);
return stack->m_length <= 0;
}
// file queue.h
#ifndef QUEUE_H__
#define QUEUE_H__
typedef struct queue_item
{
/// pointer to the next item in the queue
struct queue_item *m_next;
/// item data
int m_item;
} queue_item_t;
typedef struct queue
{
///number of items in the queue int m_length;
///first item in the queue struct queue_item *m_head;
///last items in the queue struct queue_item **m_tailnext;
}queue_t;
///creates a new queue and returns it queue_t *queue_create ();
///destroys the queue and frees resources void queue_destroy (queue_t *queue);
///pushes an item into the queue adding it to the queue's tail int queue_push (queue_t *queue, int item);
///pops the item from the queue, removing it from the queue's
head
int queue_pop (queue_t *queue);
/// checks whether the queue is empty int queue_is_empty (queue_t *queue);
#endif
// file queue.c #include <assert.h> #include <malloc.h>
#include <stddef.h>
#include "queue.h"
queue_t* queue_create ()
{
queue_t *queue;
queue = malloc (sizeof (queue_t)); if (!queue)
return NULL;
queue->m_head = NULL; queue->m_tailnext = &(queue->m_head); queue->m_length = 0;
return queue;
}
void queue_destroy (queue_t *queue)
{
queue_item_t *p; assert (queue != NULL);
for (p = queue->m_head; p != NULL; p = p->m_next) free (p);
free (queue);
}
int queue_push (queue_t *queue, int item)
{
queue_item_t *p; assert (queue != NULL);
assert (queue->m_tailnext != NULL);
// create new queue item and insert it into tail p = malloc (sizeof (queue_item_t));
if (!p) return 0;
p->m_next = NULL; p->m_item = item;
*queue->m_tailnext = p; queue->m_tailnext = &(p->m_next);
++queue->m_length; return 1; }
int queue_pop (queue_t *queue) { queue_item_t *p;
assert (!queue_is_empty (queue));
// detach head and return the item p = queue->m_head;
if (p) {
int item = p->m_item; queue->m_head = p->m_next;
//if the last one was removed than
//we should reset our tail
if (queue->m_tailnext == &(p->m_next)) queue->m_tailnext = &(queue->m_head);
free (p);
--queue->m_length;
assert (queue->m_length >= 0); return item;
}
assert (1 != 1);
// should not happen return 0;
}
int queue_is_empty (queue_t *queue)
{
assert (queue != NULL);
return queue->m_length <= 0;
}
Для работы с библиотекой следует подготовить проект с главной функцией main(), в которой с помощью директивы #include подключаются файлы, расположенные в созданной статической библиотеке. Для этих файлов необходимо указать путь, где они расположены. Обычно это делается с помощью нотации "..\..\stack.h", которая указывает, что файл stack.h находится на два уровня выше, чем функция main(), в которой он будет использоваться.
Настройка проекта с главной функцией main() выполняется при установке режима компиляции языка С системы MS Visual Studio 2010. Для этого в
меню системы MS Visual Studio последовательно выбирается File New Project. Далее из списка типа проекта Project types также последова-
тельно выбираются Visual C++ Win32 Win32 Console Application. В поле
Name прописывается имя проекта, например Lab20. Далее осуществляется настройка проекта в режиме компиляции языка С (см. тему 1).
При настройке параметров компилятора дополнительно необходимо указать компилятору пути к заголовочным файлам stack.h и queue.h, содержащим объявления интерфейса созданной библиотеки containers. Это можно сделать в пункте Additional Include Directories (дополнительные каталоги с заголовочными файлами) на странице свойств [C/C++]|[General]. Затем указывается путь к папке containers, в которой находятся библиотечные файлы stack.h/stack.с и queue.h/queue.с в виде ..\..\containers\ containers.
Форма с установкой пути к созданной статической библиотеке показана на рис. 20.13.
Рис.20.13. Установка пути к файлам созданной библиотеки
После настройки параметров компилятора необходимо выполнить настройку параметров компоновщика (Linker). На этапе компоновки происходит подключение статической библиотеки, из нее извлекается код уже скомпилированных функций, которые используются в основном проекте (с главной функцией main()). Кроме кода функций, компоновщик при необходимости извлекает из статической библиотеки совместно используемые глобальные переменные. После того как все ссылки на функции и переменные будут разрешены, компоновщик выполняет вычисление машинных адресов для функций и переменных в конечном исполняемом модуле.
На странице свойств [Linker]|[Input] необходимо указать путь к объектному файлу библиотеки. Форма с установкой свойств компоновщика показана на рис.20.14.
Рис.20.14. Настройка компоновщика Linker Input Additional Dependencies
После выполнения всех настроек можно компилировать программу и запускать ее на выполнение.
Проект с главной функцией main() и включенными заголовочными файлами из созданной библиотеки представлен на рис.20.15.