пятница, 25 марта 2011 г.

[Часть 1] Cmake: автоматизированная сборка и установка

Суть сего поста запечатлеть опыт который я получил.

Пускай есть большой проект Project состоящий из n-го числа под проектов:
project_name - основной результат проект, приложение.
project_core - основные библиотеки проекта
project_test1 - тест 1
project_test2 - тест 2
project_some -вспомогательные приложения которые сопровождаются вместе с основным проектом.
Каждый из проектов в свою очередь, помимо самого проекта, может содержать некоторые внешние данные, это могут быть конфиги, сторонние библиотеки, и прочее.
Предположим что проект пишется платформенный.
Тогда возможна следующая иерархия для вспомогательных данных
.\ - Корневая директория проекта
.\resource

.\resource\etc- конфигурационные файлы
.\resource\etc\project_name
.\resource\etc\project_name\linux - специфичные конфиги для linux
.\resource\etc\project_name\win - специфичные конфиги для window
.\resource\etc\project_name\. - общие конфиги для project_name

.\resource\etc\project_test
...
.\resource\etc\project_some
...
.\resource\etc\. - общие конфиги для всех проекто
.\resource\bin - тут например могут быть скрипты запуска
... иерархия аналогично etc
.\resource\lib - внешние библиотеки
... иерархия аналогично etc
много ? много ! Но зато все на своих места.

Далее что мы хотим сделать. А сделать мы хотим следующее.

1. Что бы cmake все это добро собрал в коталог компиляции в следующем виде
.\build\etc - все конфиги, само собой с учетом linux или win
.\build\bin - так же как etc
.\build\lib - так же как etc
2. Подготовить make install что бы в итоге получить назависимые сборки для разных подроектов
\DESTDIR\project_name\
\DESTDIR\project_name\etc
\DESTDIR\project_name\bin
\DESTDIR\project_name\lib
\DESTDIR\project_test\
...
\DESTDIR\project_some\
...
Сборка со всех файлов директории resourse/lib во едино.
set (CMAKE_SOURCE_BIN_DIR ${CMAKE_SOURCE_DIR}/resource/bin)
set (CMAKE_SOURCE_ETC_DIR ${CMAKE_SOURCE_DIR}/resource/etc)
set (CMAKE_SOURCE_LIB_DIR ${CMAKE_SOURCE_DIR}/resource/lib)

set (REGEX_BIN_FILE "[^.][a-zA-Z0-9_]*.[.a-zA-Z0-9]*")
set (REGEX_ETC_FILE "[^.][a-zA-Z0-9_]*.[.a-zA-Z0-9]*")
set (REGEX_LIB_FILE "[^.][a-zA-Z0-9_]*.[.a-zA-Z0-9]*")
# Получаем все файлы из директории ${CMAKE_SOURCE_BIN_DIR}/*
# в виде относительного пути RELATIVE ${CMAKE_SOURCE_BIN_DIR}
# от этой же директории.
# Таким образом в переменной LISTS_BIN_DIR у нас будут имена всех файлов,
# включая системные и директории, нужной нам директории CMAKE_SOURCE_BIN_DIR
FILE(GLOB LISTS_BIN_DIR RELATIVE ${CMAKE_SOURCE_BIN_DIR}
${CMAKE_SOURCE_BIN_DIR}/*)

# пробегаем по всем файлам
FOREACH(BIN_DIR ${LISTS_BIN_DIR})
# выбирая только директории (они же папки проектов)
if(IS_DIRECTORY ${CMAKE_SOURCE_BIN_DIR}/${BIN_DIR})
# сохраняем список проектов
SET(LIST_DIR_PROJECT ${LIST_DIR_PROJECT} ${BIN_DIR})

if (WIN32)
# копируем и перименовавыем все bin файлы проекта
FILE(GLOB ${BIN_DIR}_BIN_FILES
RELATIVE ${CMAKE_SOURCE_BIN_DIR}/${BIN_DIR}/win
${CMAKE_SOURCE_BIN_DIR}/${BIN_DIR}/win/${REGEX_BIN_FILE})

FOREACH(BIN_FILE ${${BIN_DIR}_BIN_FILES})
# в начале файл нужно скопировать в папку назначения
# незабываем что для VS нужно копировать в Debug и в Release
FILE(COPY ${CMAKE_SOURCE_BIN_DIR}/${BIN_DIR}/win/${BIN_FILE}
DESTINATION ${CMAKE_BINARY_DIR}/Debug/bin)
# переименовываем файл, добавляя название его проекта
FILE(RENAME ${CMAKE_BINARY_DIR}/Debug/bin/${BIN_FILE}
${CMAKE_BINARY_DIR}/Debug/bin/${BIN_DIR}_${BIN_FILE}
)
# знаете способ сделать это за одну операцию, пишите в коментах
ENDFOREACH(BIN_FILE)
#...
# повторить эту же операцию для файлов проекта
# не зависящих от архитектуры; папка: ${CMAKE_SOURCE_BIN_DIR}/${BIN_DIR}
#...

# заполняем переменную имя_проекта_BIN_FILES
FILE(GLOB ${BIN_DIR}_BIN_FILES
${CMAKE_SOURCE_BIN_DIR}/${BIN_DIR}/win/${REGEX_BIN_FILE})

else (WIN32)
# Для linux повторяем туже операцию
# ...
endif()

# добавляем к имя_проекта_BIN_FILES общие файлы проекта
FILE(GLOB ${LIB_DIR}_BIN_FILES ${${BIN_DIR}_BIN_FILES}
${CMAKE_SOURCE_BIN_DIR}/${BIN_DIR}/${REGEX_BIN_FILE})

# добавляем список файлов проекта в список всех bin файлов сборки
FILE(GLOB BIN_FILES ${BIN_FILES} ${${BIN_DIR}_BIN_FILES})

# добавляем к списку файлов проекта файлы относящиеся ко всем проектам
FILE(GLOB ${BIN_DIR}_BIN_FILES ${${BIN_DIR}_BIN_FILES
${CMAKE_SOURCE_BIN_DIR}/${REGEX_BIN_FILE})

endif()
ENDFOREACH(LIB_DIR)

# Добавляем в общий список lib файлов файлы относящиеся ко всем проектам
FILE(GLOB BIN_FILES ${BIN_FILES} ${CMAKE_SOURCE_BIN_DIR}/${REGEX_BIN_FILE})
И того мы имеет:
1. файлы всех проектов из директории resourse/bin/projectN будут скопированы в директорию build/bin и переименованы (удобно уметь для всех проектов файлы start.sh, stop.sh)
2. Для каждого из проектов будет определена своя переменная (имя_проекта_BIN_FILE) со списком всех BIN файлов требуемых для этого проекта.
3. Переменную со списком всех BIN файлов
4. Переменную LIST_DIR_PROJECT со списком всех проектов для которых существует директории в resourse/lib (это не обязательно все проекта сборки)

Такую же операцию проводим и для etc и lib файлов.
Далее нам останется сделать
list(REMOVE_DUPLICATES LIST_DIR_PROJECT)
что бы получить список всех проектов сборки (мы как бы получаем объединение всех найденных проектов в etc lib bin, т.к. некоторые из проектов могут не содержать своих директории в одной из рассматриваемых директорий, и полагаться на какую то одну не вполне надежно)

Комментариев нет:

Отправить комментарий