Крапелька рефлексії для С++. Частина друга: публікація на GitHub



Ця стаття є другою в циклі про бібліотеку cpprt, призначеної для додавання та використання мінімальної метаінформації про класи З++.

На відміну від першої статті, тут майже нічого не буде про самій бібліотеці cpprt. Я постарався максимально докладно і абстрагуючись від своєї бібліотеки викласти історію оформлення бібліотеки для її цивілізованою публікації на GitHub.

У статті порушуються питання ліцензування, структури проекту і досить багато уваги приділяється CMake.

Посилання на всі статті циклу1. Про розробку
2. Про підготовку до публікації
3. Про результат




0. Вступ

Щоб відтягнути необхідність говорити якісь вступні слова, представлю структуру даної публікації:

Розділ №0. Даний розділ. Опис структури публікації і вступні слова.
Розділ №1. Трохи про ліцензування.
Розділ №2. Трохи про створення окремого git-репозиторію підпроекту з git-репозиторію основного проекту.
Розділ №3. Думки про структуру проекту взагалі та спроби аналізу структури декількох існуючих репозиторіїв.
Розділ №4. Уроки CMake на базі хроніки розробки cmake-конфігурації для проекту cpprt.
Розділ №5. Кілька слів і багато посилань з приводу документації.
Розділ №6. Короткий розділ з думками про просування бібліотеки.
Розділ №7. Висновок і титри.

Так. Структура є і ще потрібно з чогось почати… Ладно, давайте так.

Мета статті: Розповісти про те, як я готував бібліотеку до публікації на GitHub.

Я працював над статтею, паралельно досліджуючи деякі аспекти світу відритого. На мій погляд, завдяки цьому стаття може бути цінна людям, що знаходяться лише на початку шляху: їм не доведеться лазити по всій мережі в пошуках матеріалу, я постарався зберегти тут по максимуму посилання на сайти, з якими мені довелося пройтися щоб зібрати репозиторій.

Я прекрасно віддаю собі звіт в тому, що репозиторій, як і стаття, далекі від ідеалу. Пишіть в лічку, пишіть коментарі, дивіться бібліотеку, коммите в бібліотеку – я не забуду згадати автора внесених пропозицій в титрах до статті. Кожна ваша правка допоможе людям, які будуть йти в світ відкритого ЗА вашим шляхом!

Багато пафосу нагнав… Ладно, тепер трохи історії. У першій статті циклу я згадував, що класи і макроси бібліотеки cpprt використовувалися в рамках мого бльшего проекту. Вони не були окремо виділені і жили просто як частину вихідного коду. Але в якийсь момент я помітив, що у даних класів майже немає залежностей від основного проекту, а їх функціонал самодостатній і застосуємо для деяких типових завдань.

І ось тоді-то я задумав виділити частину проекту в окремий підпроект і здійснити давню мрію: опублікувати бібліотеку з відкритим вихідним кодом.

Перед тим як читати далі, вам, ймовірно, буде цікаво ознайомитися з наступними думками (якщо ви не читали першу статтю): визнання істинних підступних мотиви даних публікацій (посилання).

І ще два попередження читає:

Дисклеймер про ліньЦя стаття практично не містить моїх думок. Це деяка компіляція різноманітних джерел. Вся справа в тому, що якщо перша стаття циклу стосувалася безпосередньо розробки (творчого процесу), то тут розповідається про якихось прийнятих стандартах та методики, які повинні чітко регламентуватися і, бажано, мати якомога менше самодіяльності. Звідси невелику кількість власних думок і велика кількість посилань.

Зауваження про термінологічний хаосХочу також відразу визнати певний термінологічний хаос, який панує в статті. «Солюшены», «шляхи пошуку хедерів», «цілі збірки» та інші… Я пробував зрозуміти як прийнято іменувати всі ці поняття по-російськи, але так і не знайшов прийнятної системи іменування. Пишіть в лічку, або у коментарі, поясню якщо який-небудь термін не ясний і внесу правки в іменування, якщо підкажіть якусь загальноприйняту термінологію.


Якщо мені так і не вдалося відбити у вас бажання читати цей опус – поїхали!

1. Вибір ліцензії



Є одна штука, яка незалежно від якості коду робить вихідні коди вагоміше в моїх очах. Можливо, комусь це здасться смішним, але для мене це шапка із зазначенням ліцензії. Ось дивлюся: є шапка – значить проект дійсно цікавий. Немає шапки – не так круто. Це якось працює автоматично, на рівні підсвідомості.

Тому коли я вирішив опублікувати бібліотеку, першим ділом руки свербіли включити в неї інформацію про ліцензування у вихідні. А для цього, у свою чергу, потрібно було обрати ліцензію.

Я починав дослідження питання ліцензування з побоюванням. Завжди побоювався цієї теми. Думав: виберу якусь не ту ліцензію – і ось вже зобов'язаний безоплатно підтримувати код до кінця днів, не маючи при цьому ніяких прав, включаючи права голосу.

На практиці все виявилося не так страшно – у всякому разі, якщо говорити про ліцензії для відкритого (з власницькими ліцензіями я поки не розбирався). Єдине, що важливо пам'ятати при виборі – так це те, що подібні ліцензії бувають двох типів: open source free software. Звучить схоже, але між ними є, як кажуть в Одесі, дві великі різниці. Розберемося докладніше:

Open source. Обережно, open source «open» неспроста! Open source перетворює в open source будь-код, який його використовує і при цьому исходники будь-якого open source коду повинні бути відкриті на першу вимогу.
Ось ви, наприклад, використовуєте у своєму проекті бібліотеку під який-небудь open source ліцензією. Використовуєте рік, використовуєте два… І раптом у вас просять, щоб ви показали весь свій код. І ви не маєте права відмовитись! Примусовий IT-комунізм. «Від кожного по первісного вигляду, кожному по первісного вигляду». Якщо вас така перспектива лякає — слідкуйте за ліцензіями проектів, які підключаєте.
Набір пунктів, що потребують відкривати код в рамках сімейства ліцензії open source, має свою назву: копілефт. Основною ліцензією, що включає в себе копілефт, є ліцензія GPL (General Public License) і споріднені їй.
Переваги: Повна відкритість коду, що дозволяє підвищити його якість за рахунок більш широкої аудиторії читачів та прискорити його розробку за рахунок більш широкої аудиторії письменників. Ну і, звичайно, ще одна перевага – ви відчуваєте, що приносите світу добро. Make open source, not war!
Недоліки: Обмежена можливість застосування продуктів під GPL-ліцензії в проприетарном коді і/або код, що містить комерційну таємницю. Яка ж це таємниця, якщо про неї потрібно розповісти на першу вимогу?

Free software. Ліцензії free software дозволяють користувачу робити з кодом що завгодно без яких-небудь обмежень, іноді з якими-небудь чисто умовними вимогам (наприклад, із зобов'язанням вказувати автора оригінальної бібліотеки). Однією з таких ліцензій є, наприклад, ліцензія MIT. Сюди також входить сімейство ліцензій BSD.
Переваги: Додаткові якісні коміти від щедрих комерційних компаній.
Недоліки: Жадібні компанії можуть потягти код собі, форкнуть в корпоративний репозиторій і тихенько розвивати його тільки для себе, не ділячись з спільнотою.

Library public license. Осібно серед ліцензій для відкритого вихідного коду коштує ліцензія LGPL (Library General Public License) і споріднені їй. Даний тип ліцензій включає в себе ознаки як open source, так і free software.
LGPL дозволяється вільно використовувати код, скомпільований в бінарне представлення (виконуваний файл або динамічну бібліотеку) де завгодно, в тому числі у ваших комерційних проектах без обмежень і без необхідності відкривати ваш код.
Але якщо вам захочеться статичного зв'язування исходников проекту під ліцензією LGPL з кодом свого проекту – ласкаво просимо в світ open source з усіма його плюсами і мінусами. Прошу ділитися кодом свого проекту.
Як приклад проекту, що використовує LGPL, можна навести Qt. За рахунок LGPL-ліцензування його динамічними бібліотеками можна користуватися в проприетарном без обмежень (обговорення на офіційному форумі Qt та аналогічне обговорення на сайті qtcentre).
Переваги: Непряма зацікавленість в якості коду комерційних організацій (їм же хочеться, щоб код зібраної бібліотеки працював добре) і, одночасно, заборона на розвиток LGPL-проекту «нишком», як це можливо з ліцензіями free sofrware.
Недоліки:Щоб використовувати бібліотеку під ліцензією LGPL в проприетарном, доведеться самому організовувати зв'язування свого продукту із зібраною в dll (або в so) бібліотекою, що зажадає нехай невеликих, але все ж зусиль.

Якщо знаєте про якісь ще цікаві ліцензії – можете написати про них у коментарях. Думаю, це всім буде цікаво.

Вивчивши існуючі ліцензії, я зупинив свій вибір на ліцензії MIT, як на одного з найбільш ліберальних ліцензій. Серед даних посилань в кінці даного розділу є кілька про ліцензію MIT. Там ній розказано досить добре, я краще не буду переповідати, щоб не спотворювати суть.

В кінці розділу хочу коротко розповісти про те, як я додав ліцензійну інформацію в свій проект (один з варіантів оформлення):

1. Поклав в корінь репозиторію файл licence.txt (або LICENCE.txt щоб помітніше було) з текстом ліцензії, який скопіював ось з цієї сайту.
2. У всі файли вихідного коду додав шапку наступного виду:

Приклад ліцензійної шапки////////////////////////////////////////////////////////////////////////////////
//
// <ім'я файлу>
//
// Copyright © <року дії ліцензії> <ім'я автора> (<опціонально, пошта автора>)
//
// Distributed under <назва ліцензії> (See file accompanying LICENSE.txt or copy at
// <шлях до сайту ліцензії>)
//

Примітка: Я зустрічав кілька репозиторіїв, в рамках яких шапки для вихідного коду додавали повний текст ліцензій. Можливо, так ви захистите код надійніше, але будете дратувати користувача, який буде перегортати це ваше довгий ліцензійне вступ для кожного файлу, з яким має справу.


Закінчу розділ я, як і обіцяв, списком посилань на цікаві матеріали:

Корисні посилання1. Ось цю статтю я читав першої. 2002 рік, ага, стаття неймовірно стара, але, начебто, більш або менш актуальна, а в самій статті є зручна порівняльна табличка для шести різних open source і free software ліцензій. Якщо такої таблички мало — можна глянути більш потужну табличку на вікіпедії.
2. Про основні open source ліцензії в одній картинці.
3. Про ліцензії откытого трохи докладніше.
4. Про open source ліцензії зовсім докладно. Інформація про ліцензію MIT в рамках тієї ж статті.
5. Зовсім докладно про MIT-ліцензію, з історичними екскурсами.
6. Докладна стаття про MIT-ліцензію. Крім цього, цікава деякими думками про відкрите ПЗ взагалі.
7. Дуже докладна стаття з філософією від GNU-спільноти на тему різниці між free software і open source.
8. Цікава стаття про те, що не все так просто у світі відкритого ПЗ.
9. Стаття зі сміливою і цікавою ідеєю: створити ліцензію, вимагає відкривати не вихідний код, а тести і результати роботи тестів.
10. Запитання, який я колись ставив на тостері (цікаво було перечитати зараз, в березні 2016-го року). В цьому питанні користувач з ніком @littleguga порадив мені ліцензію MIT, якої я, зрештою, скористався.


2. Відчеплення коду від основного проекту



Буває так, що код, який хочеться перетворити в бібліотеку, не виділений в окремий репозиторій. Він може жити з початку роботи над проектом в рамках якої-небудь папки основного сховища і, здається, історія редагування цих вихідних намертво зчеплена з історією основного проекту і шансів відчепити її немає ніяких.

На щастя, все не так сумно. У подібних випадках можна використовувати механізм git subtree split. Я навчився цього трюку ось тут (тут згадується, а от оповідання про альтернативному методі, filter-branch). Якщо буде цікаво, я можу як-небудь докладніше розповісти про те, які пригоди пережив з цим кам'яним молотом в руках, розколюючи монолітні репозиторії на подмодули і склеюючи з них різні штуки з допомогою submodule. Тут же я лише коротко опишу, як можна переселити історію редагування якоїсь окремої папки основного сховища в окремий репозиторій:

1. cd {main-repo-path}Для початку потрібно перейти в корінь основного репозиторію (того репозиторію, від якого ми будемо відчіпляти папку).

2. git subtree split -P {submodule-relative-path} -b {submodule-branch}{submodule-relative-path} — шлях, відносно кореня репозиторію, до папки, яку будемо ізолювати в гілку.
{submodule-branch} — гілка, яку скопіюється вся історія роботи з исходниками папки, розташованої по шляху {submodule-relative-path}.

Після виклику цієї команди в локальний репозиторій додасться гілка {submodule-branch}, що містить всі коміти, пов'язані із змінами в папці {submodule-relative-path}. Виклик цієї команди лише створить нову гілку і скопіює у неї коміти, нічого іншого змінено не буде.

Зауваження: Варто зазначити, що отримати меседжі, прив'язані до скопійованим коммитам, залишаться не зміненими. Вони можуть зберегти зайву для історії редагування папки інформацію (у разі якщо в якихось коммитах були зміни і в папці і поза її). Я не знаю, як цього уникнути і не думаю, що можна взагалі якось цього уникнути.

3. git push {submodule-repo-URL} {submodule-branch}:{master}Push для нової гілки в інше сховище.

{submodule-repo-URL} — URL ремоут репозиторію, в який ми хочемо поселити історію змін папки.
{master} — ім'я, яке отримає гілка {submodule-branch} ремоут-репозиторії {submodule-repo-URL}. Якщо це перша гілка, що додається в репозиторій, то, слідуючи давній традиції іменування головних гілок git, найкраще називати її «master».

Після виклику цієї команди, в репозиторій, розташований по URL {submodule-repo-URL} буде додана нова гілка з ім'ям {master}, що містить в собі історію змін папки {submodule-relative-path}.

4. git branch -D {submodule-branch}Якщо вам більше не потрібна гілка з історією редагування папки {submodule-relative-path} — варто видалити цю гілку. -D-велика означає, що ми форсим видалення гілки. Якщо видаляти гілку через -d, то git буде лаятися: мовляв, ми цю гілку нікуди не пушнули перед видаленням (git чогось не відстрілює, що ми її насправді пушнули в інший репозиторій).


Загалом, все. Виконавши описані кроки для свого основного проекту, я ізолював історію редагування вихідного майбутньої бібліотеки cpprt, отримавши таким чином дуже чорнової репозиторій і зберігши всю історію змін її файлів (нехай і з деяким сміттям в комміт-меседжі).

Репозиторій був готовий… Але до публікації було ще далеко. Ще належало привести репозиторій до належної увазі. Для цього одних джерел і ліцензії було мало. Потрібно було потурбуватися створенням купи супровідних матеріалів: тестів, прикладів, продумати механізм складання всього що вміє збиратися, створити всякі read me файлів, документації і т. д… Для всього цього слід продумати структуру репозиторію. Наступний розділ статті присвячений структурі проекту.

Корисні посилання:
1. Запитання, який я ставив колись, вибираючи між submodule і subtree. Там є досить довге обговорення і багато посилань (частину з них я вже використовував вище). Можливо, тим, хто цікавиться темою модульної організації проекту, може бути цікаво почитати дискусію і полазити по посиланнях. До речі, хочу, скориставшись нагодою, подякувати користувача Andy_U за активну дискусію в обговоренні цього питання – незважаючи на те, що я, зрештою, вибрав submodule.
2. Ще один запитання, в якому я описав труднощі, з якими зіткнувся при спробі роботи з subtree… до Речі, можливо, хто-небудь зможе пояснити що я робив не так?

3. Думки з приводу структури репозиторію



Отже, структура репозиторію… На мій погляд, це щось з розряду архітектури. Архітектура коду визначає принципи взаємодії його елементів один з одним. Архітектура – вона ж структура репозиторію вашого проекту задає принципи взаємодії з ним інших проектів. Під поняттям «інші проекти» я розумію тут не тільки кодобазы, системи збірок або бізнес процеси. Я маю на увазі також людей, які будуть користуватися вашим кодом і будуть вносити в нього свої зміни.

Я спробував в силу свого розуміння сформулювати вимоги до проекту з точки зору користувача і з точки зору контрибутора.

Погляд з позиції користувача бібліотеки



Перерахування вимог у порядку їх виникнення при знайомстві з бібліотекою:
1. Хочу розуміти, з чим маю справу. Який-небудь ридмик з коротким описом про це в корені проекту, і щоб він відображався на сторінці проекту в GitHub. Ну і, звичайно, документація. Бажано, з картинками.
2. Я хочу глянути як працювати з кодом. Тести, приклади використання коду, і щоб при цьому було зрозуміло, як воно збирається.
3. Про сам проект… Хочеться витрачати мінімум нервів і часу на складання, налаштування та інтеграцію. Було б круто, якщо б була папка з хедерами і зібрана бібліотека для мого компілятора і моєї платформи. Підключу, слинкую – і в продакшн і не хочу я розбиратися в цій вашій білд-системі.
Примітка: Тут і далі мова йде про специфічні для С++ речі. Для інших мов все трохи простіше… Напевно.
4. У мене платформонезависимый проект! Я хочу, щоб була можливість зібрати бібліотеку самому і без необхідності підлаштовуватися під вашу систему складання. Якщо говорити по-іншому, мені потрібен CMake (якщо не ясно, що таке CMake – нічого страшного, про нього буде сказано далі!
Додаткові вимоги:
5. Так, ваша бібліотека містить занадто багато можливостей. Можна які-небудь тулзы у постачанні? І бажано, щоб відразу зібрані.
6. Я вже давно використовую ваш проект. Чув, він оновився недавно? Хочу знати, що змінилося.

Отже, з урахуванням поданих вимог, виходить наступна структура:

Про позначення запису файлових деревУ статті використовується наступна нотація для опису файлових дерев:

file_in_root
Файл, що знаходиться в корені дерева файлів. До будь-якого елементу файлового дерева можуть бути додані коментарі. Даний текст є коментарем до файлу file_in_root. Коментар пишеться під записом файлу/папки, або, якщо поміщається в одному рядку, праворуч від запису.

/folder_in_root
Папка, що знаходиться в корені дерева файлів.

-file_in_folder
Файл, що знаходиться в певній папці. Щоб зрозуміти, в якій папці лежить файл, треба глянути елементи файлового дерева вище. Кількість дефісів задає рівень вкладеності. В даному випадку один дефіс означає, що файл лежить в якійсь папці, яка, в свою чергу, знаходиться в корені файлового дерева.

-/folder_in_folder
Папка, що знаходиться в іншій папці, що лежить в корені файлового дерева.



1. Що за бібліотеку?
README.txt — короткий опис проекту.
/doc — тут лежать файли, детально описують проект і його API.

2. Тести і приклади.
/tests — тестові проекти, які максимально просто запустити.
/examples — приклади, які теж повинні запускатися як можна простіше.

3. Мені б швиденько підключити...
/include — інтерфейс для доступу до API зібраної бібліотеки.
/lib — складання вихідних в статичну бібліотеку.
/bin — складання вихідних в динамічну бібліотеку.
Примітка: Папки lib і bin, бажано, повинні містити складання основних компіляторів і платформ.

4. Хочу зібрати сам!
/src — вихідні коди проекту.
cmake_readme.txt — опціональна інформація про те, як працювати з cmake-файлами для генерації конфігурацій проекту.
CMakeLists.txt — файл з конфігурацією складання.

5. Інструменти? Давайте ось сюди:
/tools — тулзы, що полегшують роботу з бібліотекою. Або зібрані, або у вигляді джерел.

6. Оновлення
change_list.txt — інформація про останні зміни в проекті.

Погляд з позиції контрибутора бібліотеки



Перерахування вимог у порядку їх виникнення при знайомстві з бібліотекою:
0. Швидше за все, на першому етапі знайомства з бібліотекою я не контрибутор – я користувач. Тому, як мінімум, в мої вимоги входять зазначені вище вимоги користувача.
1. Мені подобається ваш проект, і я хочу його розвивати. Я хотів би почитати який-небудь ридмик з приводу того, як влитися в дружну сім'ю контрибуторів.
2. Я хочу зрозуміти, як влаштована бібліотека зсередини. Мені потрібна поглиблена документація для розробників. В ідеалі документація потрібна також до системи складання проекту.
3. Я не хочу лазити по всьому проекту при роботі з білд-системою. Якщо збірка вимагає якогось велику кількість конфігураційних файлів, або додаткових програм – нехай лежить в окремій папці… Взагалі, у всьому має бути порядок, файли повинні бути згруповані за призначенням.
Додаткові вимоги:
4. Користувальницькі тулзы – це, звичайно, добре… Але проект реально великий. Потрібні якісь інструменти для розробників.

Разом, з урахуванням вимог, виходять наступні уточнення структури ідеального проекту:

1. Вступна інформація:
contributors_README.txt — короткий опис проекту для бажаючих вкласти сили в його розвиток.

2. Документація:
/doc
-/developer_doc — документація з деталями реалізації проекту.
Примітка: При такій структурі власну документацію варто також відкласти в окрему папку в рамках папки doc (в яку-небудь user_doc). Така організація документації, за моєю задумом, крім структурної впорядкованості, інтригувала б допитливого читача доки поглядати: «що ж там усередині доки для присвячених?» — і, таким чином, робила б читача вірогідним контрибутором.

3. Порядок у проекті:
build
Папка з білд-системою. Бажано, щоб поза цієї папки за проектом бовталося мінімум файлів білд-системи.

4. Інструменти для розробки:
/tools
-/developer_tools
Аналогічно документації, зібрати тулзы за їх призначенням: користувальницькі окремо, разработчиские окремо.

Перелічені вимоги стосуються суб'єктивно мого сприйняття. Якщо у вас є які-небудь свої думки з приводу — поділіться.

Під час аналізу проектів з GitHub я помітив, що в них часто згадуються файли для роботи з утилітою CMake. Більше того, судячи за деякими матеріалами, саме CMake вплинув на формування класичної структури репозиторію відкритого міжплатформового ЗА на З++. Визрівало почуття, що його не обійти. Чекав…

4. Шлях до пізнання CMake



Подяки: Спасибі Станіславу Макарову (Nipheris), спілкування з яким стало для мене поштовхом до вивчення CMake.

CMake — утиліта, що дозволяє генерувати конфігураційні файли конкретних make-систем (і/або проекти деяких IDE) для збирання С/С++ проектів на основі універсальної, абстрактної конфігурації (список підтримуваних систем збирання/IDE). Після генерування вже конфігурації і/або файли проектів, що отримуються на виході з CMake, використовуються конкретними механізмами складання; тільки в результаті їх роботи виходить зібраний продукт.
Можна сказати, що CMake — це meta-make tool, абстракція над системами збірок C/C++ проектів.

Зізнаюся, при формуванні структури сховища для бібліотеки cpprt я всіляко ухилявся від використання CMake. Типова прокрастинація… Я придумував різноманітні відмовки, складав свої білд-системи на пітоні, батники і ще фіг знає на чому, городив якісь тендітні конструкції на подмодулях. Апофеозом всього цього безумства стала ціла теорія, що обгрунтовує мій відмова від CMake. Мовляв, так як бібліотека cpprt дуже маленька (всього два файли), для її інтеграції досить вставити вихідний код бібліотеки «прямо в проект користувача подмодуль. А исходники прикладів і тулзов теж потрібно порозпихати по подмодулями — щоб користувач міг їх за бажанням підтягувати в ріпу бібліотеки.
Причому, так як у прикладів і тулзов є залежності від бібліотеки cpprt, саму бібліотеку (увага!) потрібно теж вбудувати в ці подрепозитории як підмодуль. Приклади адже, повинні показувати як треба вбудовувати бібліотеку в проекти…

Таким чином, на підставі такої єретичної теорії, я пошив репозиторій, немов чудовисько Франкенштейна, з декількох міні-репозиторіїв, з'єднаних воєдино механізмом git. Це було справжнє трешище (можете помилуватися тут). І робилося все це, якщо відкинути відмовки, з єдиною метою – лише б не вчити CMake.

Але совість не телевізор, їй звук не вимкнеш. Натикаючись на випадкові матеріали в процесі вільного пошуку, я поступово переймався усвідомленням: CMake — один зі стовпів сучасного світу відкритого міжплатформового для С++. Робити подібний проект без використання CMake – повна нісенітниця. Це зовсім неправильно, а розповідати людям про таке рішення в статті, крім іншого, означає вчити людей поганого.

Тому у вівторок, дванадцятого числа місяця квітня, я засів за вивчення CMake. До вечора наступного дня я вже мав працюючу CMake-конфігурацію проекту і сміявся над своїми страхами. Це виявилося простіше, ніж я очікував і дуже навіть зручно.

Викладаю далі хроніку мого занурення в CMake. Сподіваюся, комусь це допоможе.

Детальніше про те, навіщо потрібен CMakeТут я постараюся розповісти про те, як люди прийшли до ідеї створення CMake. Інформація орієнтована, насамперед, на тих, хто поки смутно розуміє, в чому покликання даної утиліти. Якщо вам це і так очевидно –не читати цей спойлер.

Спочатку давайте пригадаємо, в чому полягає одна з серйозних відмінностей С++ від мов, що мають справу з байткодом (Java, C#, Python, і т. д.)? Вірно, З++ збирається в платформозависимые бінарники (тут платформа = операційна система). Це, з одного боку, надає можливість виконувати більш тонкі оптимізації коду і робить код, що складається з плюсів, дуже ефективним.

Але, з іншого боку, платформозависимость означає наявність своїх тулчейнов (тулчейн = компілятор + програма компонування + дебагер + ще якісь утиліти) для кожної з платформ. А так як стандарту, який визначає принципи конфігурування тулчейнов для складання початкового C++ немає, при створення міжплатформового коду виникає необхідність задавати специфічні конфігурації складання проекту для кожного тучлейна і IDE. Як, звучить не дуже страшно? Давайте розглянемо цю ситуацію на реальному прикладі.

От є автор кроссплатформної бібліотеки з відкритим вихідним кодом. Він хоче випустити свій твір у світ, наповнений моторошним хаосом, і хоче догодити всім потенційним користувачам його бібліотеки, давши їм можливість просто і без зайвих налаштувань зібрати як бібліотеки, так і всякі супровідні проекти.
Припустимо, наш автор бібліотеки хоче дати можливість збирати бібліотеку через Visual Studio. Він додає в репозиторій бібліотеки відповідний солюшен, додає проекти для складання тестів, прикладів і тулзов, налаштовує всю цю красу – все відмінно, бібліотека збирається через студію, тести-приклади-тулзы теж.

Але ось невдача – у деяких користувачів бібліотеки варто MinGW, який запускається через Eclipse IDE і вимагає зовсім іншої конфігурації для збірки. Исходники ті ж, принципи їх складання ті ж — але задавати їх треба в рамках іншої системи, зі своїми правилами їх опису. І користувачі MinGW+Eclipse незадоволені, вони не розуміють, чому для них конфігурацію збірки не надали. Розробник бібліотеки, зітхнувши, додає файли проектів і для Eclipse IDE, задовольняючи таким чином наявний запит… Однак тепер обурюються фанати NMake з його системою складання. Потрібно і для них конфігурацію писати… А також ще кількох інших тулчейнов і IDE. Куди не ткнися – скрізь напорись.

І найстрашніше, що в разі будь-яких змін у проекті — додавання або видалення файлів, зміни налаштувань збирання — потрібно вручну міняти всі ці конфіги і проекти IDE. Недобре розробнику бібліотеки, дуже навіть сумно стає.

Але, на щастя, є CMake! Досить створити докорінно репозиторію файл CMakeLists.txt описати в цьому файлі з допомогою мови CMake універсальну конфгиурацию складання проекту, і після цього будь-який користувач, у якого встановлена утиліта CMake.exe, зможе сам легко і просто згенерувати конфіги для конкретної використовуваної ним системи складання коду (або файли проектів для IDE), а далі виконати потрібну збірку в рамках використовуваної ним коханої білд-системи/IDE самостійно. Всі щасливі, ура!

Ось навіщо потрібен CMake. В ім'я загального зручності складання.

P. S.: Що круто, концепція CMake передбачає не тільки генерацію конфігів, але і їх автоматичне оновлення при зміні файлу CMakeLists.txt. Це може бути дуже корисно при роботі з часто оновлюваними репозиторієм. Досить забрати зміни, після чого не треба нічого настроювати: достатньо просто запустити складання проекту в рамках вашого тулчейна (або у вашій IDE). CMake самостійно оновити конфігурацію перед стартом безпосередньо збірки.

На останок — кілька додаткових зауважень. Ховаю їх під спойлери.

Про поширеному дикарстве у використанні бібліотекПісля мого знайомства з CMake, з'ясувалося, що і я сам, і деякі мої знайомі — причому, деякі вельми досвідчені, з досвідом роботи З++ за п'ять років — всі ми неправильно використовуємо більшість бібліотек з відкритим вихідним кодом. Майже всі кросплатформені бібліотеки надають просту і зручну можливість CMake-складання, а ми шукаємо або відразу зібрану бібліотеку, або, в крайньому випадку, готові файли проектів для нашої IDE — замість того, щоб за десять секунд згенерувати за допомогою CMake проекти для своєї IDE, та ще з можливістю тонкої настройки того, що саме ми хочемо збирати (саму бібліотеку, тести, приклади, тулзы, які-небудь ще супровідні проекти, і інше, та інше).
Ця історія поширеного забивання цвяхів мікроскопом нагадала мені відому сумну байку про мужика, який винайшов довгі пакетики з цукром щоб було зручніше чай в чашку сипати, але ніхто не використав ці пакетики правильно і мужик від цього покінчив з собою.

Пам'ятайте, що кожен раз, коли ви ігноруєте можливість використання CMake відкритому для С++, в світі плаче один автор бібліотеки. Використовуйте інструменти правильно.



Про те, чому 14 стандартів + 1 новий не про CMakeУ зв'язку з CMake читачеві, ймовірно, згадається відома картинка про чотирнадцять стандартів і про п'ятнадцятий, який з'являється при спробі пов'язати їх в один. Але в даному випадку ця картинка буде не до місця. Справа в тому, що CMake не потрібно вбудовувати як щось чужорідне в складальну інфраструктуру вашого проекту. Достатньо один запустити CMake, щоб отримувати зручні для складальної інфраструктури основного проекту файли конфігурації (або проектів для IDE), після чого вже ці файли (або проекти) можна буде легко вбудовувати як щось, відповідне існуючої організації вашого проекту і цільовій платформі.

CMake — це не система складання. CMake над системами складання. Він ними керує.




Меду-то скільки, меду, без єдиної молекули дьогтю… Але мінуси теж є, звичайно, і про них ми поговоримо на практиці.

Думаю, тепер, коли ви знаєте що таке CMake, навіщо CMake і наскільки CMake це добре — прийшов час з ним познайомитися. Отже, хроніка…


Всі події, викладені нижче, дійсно мали місце дванадцятого квітня 2016 року, у вівторок. Відновлено з історії запитів сторінок в моєму браузері.

(0:35) Первинний пошук матеріалів





З чого ми зазвичай починаємо? Вірно, починаємо ми з пошуку уроків.

За запитом "cmake tutorial" перша ж посилання вели на офіційну доку. В основному я розбирався з нею. Так як cpprt — проект поки дуже невеликий, розуміння перших п'яти кроків доки вистачило для описи конфігурацій усіх можливих цілей складання бібліотеки (включаючи складання тулзов і прикладів).

За запитом "CMake habrahabr" на першій сторінці Google знайшлися три статті, задумані як навчальні. Ось стаття сподобалася мені найбільше (до речі, вона ж випадає другий за запитом «cmake tutorial»). Гарна повчальна стаття, в чомусь схожа місцями на переклад доки – але більш лаконічна. Розбита на розділи, в кожному з яких розповідається про можливості CMake і даються прості приклади по справі, без зайвої лушпиння. Я використав цю статтю в якості додаткового навчального матеріалу.

Інші знайдені посилання1. туторіал по CMake. Початок мені дуже сподобалося – там навіть про структуру проекту було досить виразно і красиво написано. Але після першого невеликого і зрозумілого прикладу, автор почав різко ускладнювати приклади, я заплутався і вирішив далі все ж користуватися зазначеної вище статті.
2. Невеликий розбір CMake-збірки бібліотеки LZ4 (відносно невеликого проекту з GitHub). Можливо, що мали досвід з CMake розбір вельми непоганий – але мене, як зовсім-зовсім новачка в цій справі, він відлякав невеликим об'ємом коментарів при великому обсязі коду і багато якихось специфічних для LZ4 змінних.
3. Хороший вступний урок.

Із посилань, які знайшов вже під час серфінгу по хабру, вельми потішила ось ця упоротая стаття: стрілочний годинник на CMake . З коду не зрозумів нічого — але круто в тій же мірі, в якій дивно.


(2:00) Складання першої CMake-конфігурації





До CMake я повернувся до двох годин ночі. Коротко ознайомився з уроками і вирішив потренуватися на якому-небудь тестовому, максимально простому проекті. Я створив папку (нехай вона далі називається {cmake_test}) з наступним вмістом:

main.cpp
Тестовий файл, для складання якого ми будемо генерувати конфігурації.
Вміст файлу
#include < iostream>

int main() {
std::cout << "Hello from CMake!" << std::endl;
return 0;
}



CMakeLists.txt
Файл із описом конфігурації складання макету main.cpp. Тут і далі до кожної нової команді CMake я даю розгорнутий коментар.
Вміст файлу#Коментар до команди cmake_minimum_required і кілька слів про аргументи команд в CMakeОфіційна документація до команди cmake_minimum_required

Ця команда задає мінімальну версію CMake, яка може збирати дану конфігурацію. Використовується, щоб відразу сказати користувачеві, щоб він оновив CMake, якщо його версія дуже стара.

Так як це перша команда CMake, з якою ми зустрічаємося, зверну увагу на те, як тут прийнято передавати аргументи. Роздільником між аргументами служать whitespace-и (пробіли, таби, символи нового рядка). При цьому в CMake бувають іменовані аргументи. Так, наприклад, у представленому виклик «VERSION 2.8.8» — це передача значення 2.8.8 для аргументу іменований аргумент VERSION команди cmake_minimum_required. У виклик наступної команди (project) аргумент передається без імені.
Чесно кажучи, я не дуже зрозумів принцип, за яким CMake знає, чи передане значення аргументом або значення. Не зрозумів цього я навіть після прочитання офіційної доки з приводу синтаксису виклику команд… Втім, як мені здається, в 95% випадків без цього можна жити.

cmake_minimum_required(VERSION 2.8.8)

#Коментар до команди projectОфіційна документація до команди project

Ця команда задає інформацію про проект CMake. Це не те, що зазвичай називається проектом для IDE. Мається на увазі те, що знаходиться в проектній ієрархії на рівень вище. У Visual Studio це називають вирішенням (solution), а в Eclipse – робочим простором (workspace).
В рамках проекту CMake можуть бути задані конфігурації для складання декількох бібліотек і виконуваних файлів, а також правила їх зв'язування один з одним.

# В даному випадку ми задаємо ім'я проекту test_project
project(test_project)

#Коментар до команди add_executableОфіційна документація до команди add_executable

Додає в проект мета для складання виконуваного файлу. Цілями для складання (build target) в CMake можуть бути виконувані файли та бібліотеки (детальніше про те, що таке мета збірки – на початку розділу доки про систему складання CMake).

Перший аргумент – ім'я мети складання, після чого перераховуються шляхи до файлів вихідного коду, з яких буде збиратися виконуваний файл.
Для більш тонкої настройки є ряд додаткових аргументів, можете почитати про це на офіційній доці докладніше. Для простого проекту зазначеної конфігурації достатньо.

# В даному випадку ми додаємо на збірку один вихідний – main.cpp
add_executable(test_executable main.cpp)


build
Пуста папка. У неї ми будемо створювати конфігураційні файли за допомогою команди CMake.

Після створення всіх цих тестових файлів, я відкрив консоль і зробив наступне:

cd {cmake_test}/build
Перейшов в папку, в якій планував генерувати конфігурацію складання.

cmake -G «MinGW Makefiles» ../
Виклик для генерування конфігураційних файлів збірки через тулчейн MinGW.
-G «MinGW Makefiles» — вибір генератора для створення файлів конфігурації. Генератор – програма, яка формує файли конфігурації для конкретного тулчейна (або IDE) з абстрактної CMake-конфігурації.
В даному випадку, я хотів отримати make-файл для тулзы MinGW32-make, що йде в поставці тулчейна MinGW.
../ – шлях до папки, в якій лежить CMakeLists.txt з описом конфігурації.
Після виклику описаної команди, у папці, з якої здійснюється цей виклик, повинні були з'явитися файли конфігурації для складання проекту. В даному випадку, очікувалася конфігурація складання одного виконуваного файлу з исходника main.cpp.

Я зробив цей виклик 2:25 ночі. Час відновлено виходячи з історії запитів, а саме виходячи з часу першого запиту з приводу наступних виниклих проблем.

(2:25) Проблеми



Нічого не зібралося. CMake видав наступну помилку (залишаю тільки ту частину повідомлення, яка стосується помилки, і ховаю свої шляхи):

CMake Error at {my cmake_path}/share/cmake-2.8/Modules/CMakeMinGWFindMake.cmake:20 (MESSAGE): sh.exe was found in your PATH, here: {some path}
Run cmake from a shell that does not have sh.exe in your PATH.


Я погуглив і знайшов ось таку інформацію. У двох словах: якщо в системних шляхах доступний sh.exe, то генератор для MinGW не буде працювати. Чому – я так і не зрозумів до кінця, і о пів на третю ночі не особливо хотілося розбиратися, особливо з урахуванням того, що в моєму випадку виправити дану проблему можна було без особливих зусиль.

Я тимчасово прибрав системний шлях, з якого додавався sh.exe (в моєму випадку це був git), знову запустив CMake і… знову отримав помилку, але вже іншу. Нова помилка виглядала куди більш гнітюче (залишаю тільки ту частину повідомлення, яка стосується помилки):

Building C object CMakeFiles/cmTC_ebbab.dir/testCCompiler.c.obj
C:\MinGW\bin\gcc.exe -o CMakeFiles\cmTC_ebbab.dir\testCCompiler.c.obj -c C:\Users\test\Desktop\С'РјРї\cpprt_FINAL\current\github\build\CMakeFiles\CMakeTmp\testCCompiler.c
gcc.exe: error: C:\Users\test\Desktop\С'РјРї\cpprt_FINAL\current\github\build\CMakeFiles\CMakeTmp\testCCompiler.c: No such file or directory


Знову почитавши різні джерела, я зрозумів, що безпосередньо дана помилка виникала з наступних причин. Перед формуванням файлів конфігурації для конкретного тулчейна, CMake виконує перевірку наявності компонентів цього тулчейна (компілятора, зв'язування тощо), а також перевіряє чи правильно ці компоненти працюють. Для цього він створює в тимчасовій папці ісходник testCCompiler.c і пробує його зібрати з допомогою компілятора. І в моєму випадку CMake чомусь не створював такий файл.
На жаль, я не можу дати конкретної посилання з цього приводу, от деякі відгомони цього механізму.

Взагалі, сама помилка-то, звичайно, виникала з викладених вище причин. Але було зрозуміло, що це наслідок, а не причина. Щоб знайти причину, я гугл хвилин сорок, до початку четвертого ночі. Це було типове зависалово в дусі «на мужика»: зробити, щоб цей гребанный код працював, нарешті, і потім вже піти спати… Воно мене перемогло. Я здався першим. Ось одна з найбільш розумних посилань, які я встиг нарити до півчетвертої ночі.

Вирішення проблеми: В чому була справа з'ясувалося, вже в процесі написання даної статті. Справа в тому, що шлях до папки, в яку виконувалася збірка, містив російські символи. Варто було виконати зборку в папку, шлях до якої не мав таких вадою, як збірка make-файлу для MinGW пройшла успішно.
Висновок: Стережіться шляхів з юнікодом! Якщо щось не працює і не знаєте чому – подивіться, чи немає юнікоду в шляхах ваших і спробуйте зробити шляху без підтримки!

(10:38) Збирання Visual Studio





Прокинувся я з упевненістю, що більше не бажаю долбаться зі складанням для MinGW. У мене була встановлена Visual Studio, так чому б не спробувати на початку зібрати конфіги для неї (точніше, у випадку зі студією, збирати solution і projects), а потім потестувати генерацію конфіги для інших тулчейнов.

Я відкрив консоль, перейшов в папку {cmake_test}/build і викликав CMake, вказавши інший генератор:

cmake -G «Visual Studio 14 2015» ../

Про чудо! У папці build утворився солюшн test_project.sln, кілька проектів (ось тут я трохи здивувався – чому кілька) і ще купу всяких допоміжних файлів, потрібних для того, як я зрозумів, щоб CMake міг оновлювати налаштування солюшена і проекту у разі зміни конфігурації, без необхідності кожного разу заново генерувати конфіги.

Я відкрив солюшен. Так, мені не здалося. Крім очікуваного проекту test_executable.vcxproj для складання main.cpp у исполянемый файл, в солюшене лежали ще два якихось лівих проекту: ALL_BUILD.vcxproj і ZERO_CHECK.vcxproj. Я погуглив з приводу. Знайшов ось цей відповідь на stack overflow. З нього я зрозумів, що це саме ті проекти, за допомогою яких CMake оновлює файли проектів перед кожною складанням у разі, якщо змінився файл CMakeLists.txt, з якого ці файли проектів були породжені. Загалом, все правильно, вони і повинні були скластися.

Як позбутися від ZERO_CHECKПід час фінального формування репозиторію cpprt виникла необхідність генерувати конфігурації CMake для студії без залежностей від CMake (без проектів ZERO_CHECK і BUILD_ALL) — щоб користувачі без CMake могли запускати ці проекти. Рішення як позбутися від ZERO_CHECK знайшлося ось тут. Люди говорили, звичайно, що це багато в чому ламає саму ідею CMake (ламає оновлення конфігурацій при змінах), але розповіли все-таки, що щоб згенерувати рішення для студії без ZERO_CHECK, досить виставити опцію CMAKE_SUPPRESS_REGENERATION в TRUE (можна ось так виставити: -DCMAKE_SUPPRESS_REGENERATION=TRUE, якщо налаштовувати генерацію солюшена через командний рядок). При виставленні цієї опції, BUILD_ALL та інші супровідні файли і папки CMake, як і раніше, будуть створені, але їх можна видалити без шкоди для проекту.

Чому позбутися ZERO_CHECK виявилося замалоЦе перша чутлива незрозумілість з CMake… Справа в тому, що, як я зрозумів, CMake не вміє генерувати конфіги з відносними шляхами (relative paths). Що мається на увазі?

Наприклад, якщо ви в проекті описуєте include paths через CMake, він побудує абсолютний шлях до переданої папці, навіть якщо в конфігурації CMake ви вказали шлях відносним. І це стосується всіх шляхів для всіх конфігурацій складання, включаючи шляхів до папок, в які записують результати складання (build output directort)!

З-за описаних особливостей генерації шляхів, стає неможливим зберігати генеровані CMake конфігурації і файли проектів для IDE в репозиторіях, адже абсолютні шляхи задають прив'язку до конкретних шляхів якогось одного користувача.

Я поки не знайшов як можна вирішити дану проблему. Знайшов опцію CMAKE_USE_RELATIVE_PATHS, але в офіційній доці до неї є приписка «May not work!» і, чорт візьми, як зазвичай офіційна дока не бреше. It's not work!

цьому старому обговоренні говориться, що можливість використовувати відносні шляхи не характерна для CMake і тому її немає і не передбачається, а в трохи більш свіжому обговорення на форумі ігрового движка ogre3d, ось в це відповіді пропонується один-в-один те ж рішення, що намагався використовувати я і що мені, що форумчанам з ogre3d.

У скажу, що я здивований, наскільки дана проблема слабо висвітлена в інтернеті. На мій погляд, це досить чутлива проблема. Опція генерації конфігурацій, не залежних від cmake через cmake, мій погляд, аналогічна опції import репозиторію для систем контролю версій. Вона повинна бути.
Може, я просто погано шукав, або шукав як-небудь не так? Якщо ви як-небудь вирішили для себе цю проблему, розкажіть у коментарях як саме ви це зробили. Я перероблю ці спойлери в окремий розділ цієї статті, а вкажу вас як автора цього розділу.



У Visual Studio я вибрав проект test_executable як startup project і натиснув ctrl+f5. В консоль надрукувати: «Hello from CMake!». Урашечки ура!



З початку роботи минуло близько години.

(11:24) Підготовка репозиторію для складання через CMake



Тепер можна було спробувати підключити CMake до основного проекту. До CMake, як я вже розповідав, мій проект мав пекельну організацію на подмодулях. З урахуванням перспектив, які відкривалися завдяки CMake, від використання подмодулей можна було відмовитися. Я зробив окремий клон репозиторію, забрав исходники всіх подмодулей і почав думати, як буду налаштовувати складання з допомогою CMake.

Я злегка перебудував репозиторій, чому він став виглядати по-людськи, як бачені мною «дорослі» репозиторії. Ось частина структури проекту, яка стосується безпосередньо роботи з CMake:

build — порожня папка, в якій належить збирати исходники.
/include — папка з хедерами для доступу до API бібліотеки.
/src — папка з вихідним кодом бібліотеки.
/examples — папка з вихідним кодом різних прикладів.
-/__example_hierarchies__ — папка з тестовими ієрархіями класів (див. далі).
-/simple_examples — папка з исходниками невеликого тестового прикладу.
/tools — папка з інструментами для роботи з проектом.
-/console — в даний момент є тільки одна програмка, і ім'я їй консоль.
CMakeLists.txt — CMake-файл, за допомогою якого можна зібрати різні елементи проекту.

Поточний репозиторій бібліотеки
Те, що викладається в даній статті, вірно для коміта e9c34bb.

Подбронее про __example_hierarchies__Папка __example_hierarchies__ зберігає кілька ієрархій класів, реєстрованих за допомогою макросів cpprt. Ці класи не мають полів, вони тільки і роблять, що успадковуються один від одного, а віртуальні, теж порожні методи потрібні лише для демонстрації роботи cpprt абстрактними класами. Дані ієрархії були потрібні тому, що в бібліотеці cpprt багато уваги приділяється метаданих про спадкування класів, і ієрархії успадкування з __example_hierarchies__ можна було використовувати у різноманітних тестах і прикладах.


Я вирішив, що в рамках поставки бібліотеки можна буде збирати такі штуки:



Чорний колір для бібліотеки.
Синій колір для виконуваних файлів.
Зелений колір для папок з исходниками, шареных між цілями складання.

бібліотека
1. cpprt – власне, сама бібліотека. Збирається з вихідного коду, який знаходиться в папці /src і з інтерфейсу, який лежить в папці /include.
Збирається в статичну бібліотеку, залежностей не має.
приклад
2. simple_examples – невеликий приклад, що складається з єдиного файлу, в якому описується класична для ознайомлення з ООП ієрархія класів тварин і на базі цієї ієрархії демонструється використання API бібліотеки.
Збирається в виконуваний файл, залежить від бібліотеки cpprt.
інструмент
3. console – в даний момент це, фактично, теж приклад демонстрації можливостей бібліотеки, але в планах – перетворити його в самостійну тулзу.
Через консоль можна переглядати інформацію про деревах спадкування реєстрованих класів, а також створювати і видаляти об'єкти класів за строковим імен як об'єктів, так і класів.
Збирається в виконуваний файл, залежить від бібліотеки cpprt і від тестової ієрархії класів, на прикладі якої можна подивитися роботу консолі.

Структура була готова. Залишалося всього нічого» – описати конфігурації для складання цих артефактів за допомогою CMake.

(11:30) Складання бібліотеки cpprt





Незважаючи на те, що бібліотека cpprt містила всього два файла, я вирішив попрацювати на перспективу і відразу дізнатися, як підключати всі файли, що містяться в будь-якій папці рекурсивно (не буду ж я перераховувати десятки шляхів до исходниками коли їх стане більше). Загуглил і знайшов цю посилання, в якій розповідалося про використання команди file з аргументом GLOB_RECURSE.

Я ще мигцем глянув CMake-конфигурацию невеликого проекту Project-OSRM та написав наступний конфігураційний код з використанням знайденої інформації:


CMakeLists.txt#Коментар до команди setОфіційна документація про set

Дана команда призначена для установки або додаткового встановлення значень змінних. Перший аргумент – ім'я змінної. Потім задається її значення. В даному випадку ми передаємо шлях ".", що, як правило, означає поточну папку – тобто папку, в якій знаходиться CMakeLists.txt (в даному випадку – корінь репозиторію).

Примітка: Можна передавати змінні через командний рядок під час виклику CMake? Можна, якщо задавати змінну з передачею CACHE (вот відповідь з stack overflow з приводу). Виглядає громіздко — тому, на мій погляд, передавати прапори з командного рядка краще через команду option (про неї далі).

set(CPPRT_ROOT_PATH .)

# Задаємо значення кореневої папки для вихідного бібліотеки.
#Про посилання на змінніОфіційна документація про синтаксис посилань на змінні

CMake використовує поширений механізм доступу до значень змінних. Як сказано в доці, CMake підставляє значення змінної прямо в місце, де згадується посилання на змінну (або вставляє порожню рядок, якщо змінна з таким ім'ям не була визначена). За рахунок цього можна використовувати подібні вставки в текстові змінні (Quoted Argument) і навіть в інші посилання на змінні. Приклад з доками:

${outer_${inner_variable}_variable}

Як я зрозумів, тут значення змінної inner_variable виступає частиною імені іншої змінної. Чудеса, до і тільки.

set(CPPRT_SOURCES_PATH ${CPPRT_ROOT_PATH}/src)

# Задаємо значення кореневої папки для інтерфейсу бібліотеки.
set(CPPRT_INCLUDE_PATH ${CPPRT_ROOT_PATH}/include)

#Коментар до команди fileОфіційна документація до команди file

Я тут розповім тільки про використання команди file з аргументом GLOB_RECURSE. Така команда виконує рекурсивний пошук шляхів файлів і папок, підкоряються що задається у виклику команди правилами пошуку. Правила задаються аргументами, наступними за ім'ям змінної, в яку запишеться список знайдених шляхів.
Напевно, є ще хитрі правила – але для моїх цілей вистачило правила, задає принцип пошуку по розширенню файлів. Для завдання подібних правил треба вказати шлях до папки, починаючи з якої виконувати рекурсивний пошук файлів по даній і вкладених папок, і вказати розширення файлів, шляхи до якого ми шукаємо, залишивши замість імені файлів зірочку (так, як це прийнято в більшості операційних систем).

Команду file можна викликати не тільки з опцією GLOB_RECURSE, але і просто з GLOB. Такий виклик відрізняється лише тим, що не буде виконувати пошук у вкладених папках.

Примітка №1: При генеруванні конфігурації, CMake може додавати деякі свої вихідні файли в рамках проекту. При необережному використанні команди file GLOB_RECURSE (наприклад, якщо шукати з її допомогою исходники, починаючи прямо з кореня репозиторію) можуть виникати деякі проблеми. З однією з них я теж зіткнувсяось тут розповідається про означену проблему).
Примітка №2: Взагалі, досвідчені користувачі CMake не радять ні file GLOB, ні file GLOB_RECURSE. Ось тут пояснюється причина. Використання цих команд призводить до необхідності оновлювати генеруються конфігурації (або солюшены IDE) через CMake вручну при додаванні/видаленні файлів.

Чому не варто використовувати file GLOBСправа в тому, що, як говорилося вище, при запуску складання в рамках керованої CMake конфігурації для тулчейна (або солюшена для IDE) виконується оновлення цій конфігурації (солюшена) на підставі змін файлу CMakeLists.txt, з якого генерувалася конфігурація. Зверніть увагу — саме файлу CMakeLists.txt.
А тепер уявімо, що ми додали файл у папку, інформацію з якої CMake збирає з допомогою команди file GLOB або за допомогою команди GLOB_RECURSE. Проблема в тому, що при цьому файл CMakeLists.txt змінено не буде і при складанні оновлення конфігурацій (солюшенов) не виконується автоматично. Незручно.


Для моїх скромних завдань дана проблема поки не актуальна, але коли розберуся в ній – додам посилання на більш прийнятне рішення даної проблеми.

# Тут ми викликаємо команду для отримання шляхів до всіх исходниками
# бібліотеки. У змінній CPPRT_SOURCES буде зберігатися список
# отриманих шляхів.
file(GLOB_RECURSE CPPRT_SOURCES
${CPPRT_SOURCES_PATH}/*.h
${CPPRT_SOURCES_PATH}/*.cpp
)

# Збираємо шляху до хедерам, які входять в інтерфейс бібліотеки.
# Список шляхів до хедерам буде зберігатися в змінної CPPRT_HEADERS.
file(GLOB_RECURSE CPPRT_HEADERS
${CPPRT_INCLUDE_PATH}/*.h
)

#Коментар до команди add_libraryОфіційна документація до команди add_library

Ми вже додавали виконуваний файл в якості мети складання. Бібліотеки як мети складання додаються аналогічним чином. Єдина різниця – до перерахування шляхів до исходниками бібліотеки вказується тип бібліотеки, в яку збирається дана мета збірки: STATIC (для складання статичну бібліотеку) або DYNAMIC (відповідно, для складання в динамічну бібліотеку).

# Тут ми додаємо в проект мета для складання статичної бібліотеки cpprt.
add_library(cpprt STATIC ${CPPRT_SOURCES} ${CPPRT_HEADERS})


Після того, як файл був готовий, я перейшов в папку build і зібрав файли конфігурації:

cmake -G «Visual Studio 14 2015» ../

Все зібралося відразу: з'явився солюшн з проектом cpprt.vcxproj. Я відкрив солюшн і запустив збірку через студію… Так. Бібліотека зібралася без зайвих проблем.

Це сталося у 12:41, про що я можу говорити виходячи з часу, який відкрив посилання на фейсбучек.
Після фейсбучика я тимчасово переключився на інші завдання.

(16:09) Складання прикладу simple_examples



Налаштування cmake я повернувся через два з половиною години. Тепер належало зробити можливою генерацію конфіги для складання прикладу до бібліотеки. Для цього було потрібно розібратися з організацією залежностей між проектами – адже проект simple_examples статично линковался з бібліотекою cpprt:



Команди для лінкування статичної бібліотеки згадувалися в уроках CMake на хабре (другий приклад). Почитавши ці уроки і ще кілька джерел, я написав наступний конфігураційний код:

CMakeLists.txt#===============================================================
# Head
#
cmake_minimum_required(VERSION 2.8.8)

#Коментар до команди optionОфіційна документація до команди option

Ця команда задає значення змінної-прапорця.
Перший аргумент – назва змінної, для якої задається значення.
Другим аргументом можна передати рядковий ім'я прапора — я поки не дуже зрозумів, як його можна використовувати. Думав, можна роздрукувати всі доступні в рамках CMakeLists.txt опції з гарними поясненнями їх призначення, пошукав, але не знайшов такого вбудованого в CMake рішення, тільки різні велосипеди.
Третій аргумент – значення прапора за замовчуванням. Значення може бути встановлено користувачем при виклику генерації конфіги з командою рядка.

Дана команда зручна тим, що під час виклику генерації конфіги (виклик cmake -G і т. д. по тексту) значення опцій можна передавати як аргумент командного рядка (прочитав про це ось тут). Передавати його можна ось так:

-D<ім'я опції>=ON/OFF

Примітка: Як писалося в коментарі до команди set вище, значення з командного рядку можна задавати через CACHE-змінні. Але, на мій погляд, команда option виглядає більш витончено і тому вважаю її використання для передачі бульових значень краще.

# Тут ми задаємо прапор, який зберігає інформацію про те,
# потрібно генерувати конфіги для складання прикладів
option(BUILD_EXAMPLES «Build cpprt examples» OFF)

#-----------------------------------------------------------------------------------------------
# Збірка бібліотеки cpprt. Цей код вже був докладно розібраний вище.

project(cpprt_projects)

set(CPPRT_ROOT_PATH .)
set(CPPRT_SOURCES_PATH ${CPPRT_ROOT_PATH}/src)
set(CPPRT_INCLUDE_PATH ${CPPRT_ROOT_PATH}/include)

file(GLOB_RECURSE CPPRT_SOURCES
${CPPRT_SOURCES_PATH}/*.h
${CPPRT_SOURCES_PATH}/*.cpp
)

file(GLOB_RECURSE CPPRT_HEADERS
${CPPRT_INCLUDE_PATH}/*.h
)

include_directories(${CPPRT_INCLUDE_PATH})
add_library(cpprt STATIC ${CPPRT_SOURCES} ${CPPRT_HEADERS})

#-----------------------------------------------------------------------------------------------
###- Examples
#

#Коментар до команди include_directoriesОфіційна документація про include_directories

Дана команда додає шляхи для пошуку хедерів (воно ж inlcude paths) для всіх цілей складання в рамках поточного файлу конфігурації CMakeLists.txt.
Дану команду можна викликати кілька разів, додаючи нові шляхи – тобто вона не встановлює, вона саме додає шляхи. Можна навіть вибирати куди саме додавати нові шляхи – у кінець або на початок списку шляхів, передачею опцій BEFORE і AFTER у команду.

Зауваження: У процесі пошуку інформації про цю команду, я натрапив ще на этот відповідь. У ньому говориться, що якщо не хочеться додавати шляху пошуку хедерів для всіх цілей складання проекту, можна використовувати команду target_include_directories, яка додає шляхи для пошуку хедерів тільки для зазначеної мети складання. Нижче ми ще поговоримо про цю команду.

include_directories(${CPPRT_INCLUDE_PATH})

#Коментар до команди ifОфіційна документація до команди if

З цією командою все очевидно – вона потрібна для реалізації розгалуження. Думаю, з неї і так все ясно.

Зауваження: Передавати умова перевірки у команди else() і endif(), як це зроблено у мене, не обов'язково (офіційна документація: «Note that the expression in the else and endif clause is optional»), але, як я зрозумів, вважається хорошим тоном передавати прості умови в ці команди, щоб легше було читати код. Це зразок того, як прийнято додавати коментарі до закриває макросные перевірки #endif в плюсах.

# Якщо при складанні опція BUILD_EXAMPLES була виставлена
# значенням ON – виконуємо складання прикладу.
if(BUILD_EXAMPLES)

#- — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — -
### — Simple examples

# Зберігаємо шлях до папки з прикладами.
set(SIMPLE_EXAMPLE_ROOT ${CPPRT_ROOT_PATH}/examples/simple_examples)

# Додаємо таргет складання тестового проекту.
# Приклад повинен збиратися в виконуваний файл.
add_executable(simple_examples
${SIMPLE_EXAMPLE_ROOT}/SimpleExamples.cpp
${CPPRT_SOURCES}
)

#Коментар до команди target_link_librariesОфіційна документація до команди target_link_libraries

Виклик даної команди задає правила лінкування статичних бібліотек до мети складання. Мета збірки, до якої линкуются бібліотеки, передається першим аргументом. Далі передаються цілі збірки для бібліотек. Дану команду можна викликати кілька разів для однієї і тієї ж цілі збірки – все що передаються статичні бібліотеки будуть додані в список в порядку викликів команд target_link_libraries (з доками: «Repeated calls for the same {target} append items in the order called»).

Примітка: В доці сказано, що можна також передавати прапори для лінкування бібліотек, вже зібраних поза CMake. Сам такого не робив. Коли доберуся до даного питання, залишу тут посилання.

target_link_libraries(simple_examples cpprt)
endif(BUILD_EXAMPLES)
#========================================================


Я спробував згенерувати рішення студії з конфіги CMake: спочатку з передачею опції для складання прикладів, потім без неї. Наприклад, ось якою командою генерував солюшен для студії разом з проектом прикладу:

cmake -G «Visual Studio 14 2015» -DBUILD_EXAMPLES=ON ../

Коли генерація з прикладом пройшла, я відкрив рішення і хотів запустити приклад – але отримав повідомлення про те, що для проекту немає зібраного виконуваного файлу. При цьому не було жодної помилки.

На щастя, все було зовсім просто – я забув виставити проект прикладу в якості startup project (CMake після складання за замовчуванням виставляє BUILD_ALL, в рамках якого не збирається ні одного виконуваного файлу). Після того, як я виставив, на екрані надрукувати все що треба для тіста.

Це сталося, як я зміг відновити з історії, 17:14 – суджу по тому, на скільки я відкрив проект FastDelegate (це одна хороша микробиблиотечка для роботи з коллбеками в плюсах). Я її використовував для свого основного проекту і захотілося глянути як там білд-система зроблена. З'ясувалося, що ніяк… Втім, можливо, і правильно.

(17:14) Складання тулзы-приклад console



Залишалося зібрати консоль. В принципі, всі команди, необхідні для цієї збірки, я вже знав. Згадаймо структуру проекту:



Консоль може збиратися з тестовими ієрархіями класів. Тут під поняттям «збирається з ієрархіями класів» мається на увазі включення исходников з папки репозиторію /examples/__example_hierarchies__ в перелік джерел, з яких збирається консоль (не як header search paths, а саме як ще одне джерело исходников).

Конфігурація з описом складання консолі. Наводжу конфігурацій без описаних вище конфігурацій для складання прикладів, щоб не засмічувати код:

CMakeLists.txt#==========================================================
# Head
#
cmake_minimum_required(VERSION 2.8.8)

# Я вирішив що генерування конфіги для складання тулзы-приклад
# console можна конфігурувати двома опціями:

# чи Потрібно взагалі генерувати конфіги для складання консолі.
option(BUILD_TOOLS «Build cpprt tools» OFF)

# чи Потрібно додавати до компилируемым з консоллю файлів
# тестові ієрархії класів
option(CONSOLE_WITH_EXAMPLE «Add examples to console» ON)

#-----------------------------------------------------------------------------------------------
### — cpprt code
#
project(cpprt_projects)

set(CPPRT_ROOT_PATH .)
set(CPPRT_SOURCES_PATH ${CPPRT_ROOT_PATH}/src)
set(CPPRT_INCLUDE_PATH ${CPPRT_ROOT_PATH}/include)

file(GLOB_RECURSE CPPRT_SOURCES
${CPPRT_SOURCES_PATH}/*.h
${CPPRT_SOURCES_PATH}/*.cpp
)

file(GLOB_RECURSE CPPRT_HEADERS
${CPPRT_INCLUDE_PATH}/*.h
)

include_directories(${CPPRT_INCLUDE_PATH})
add_library(cpprt STATIC ${CPPRT_SOURCES} ${CPPRT_HEADERS})

#- — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — -
# Тут ми збираємо шляхи до всіх файлів, які знаходяться в
# папці __example_hierarchies__. Коментарі, думаю, не потрібні.

set(EXAMPLE_HIERARCHIES_ROOT
${CPPRT_ROOT_PATH}/examples/__example_hierarchies__
)

file(GLOB_RECURSE EXAMPLE_HIERARCHY_PATHES
${EXAMPLE_HIERARCHIES_ROOT}/*.h
${EXAMPLE_HIERARCHIES_ROOT}/*.cpp
)

#-----------------------------------------------------------------------------------------------
### Тут ми будемо збирати консоль

if(BUILD_TOOLS)

# Шлях до папки з інструментами – стане в нагоді на майбутнє,
# коли інструментів буде більше одного.
set(TOOLS_ROOT ${CPPRT_ROOT_PATH}/tools)

#- — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — -
# Шлях до вихідного коду самої консолі
set(CONSOLE_ROOT ${TOOLS_ROOT}/console)

# Якщо ми збираємо код з тестовою ієрархією, то:
if (CONSOLE_WITH_EXAMPLE)

# Додаємо мета складання для консолі
add_executable(cpprt_console
${CONSOLE_ROOT}/CPPRTConsole.cpp
${EXAMPLE_HIERARCHY_PATHES}
)

# Щоб було зручніше инклудить хедеры тестовій ієрархії –
# додаємо її в дорозі для пошуку хедерів (include path).
# Так як цей шлях пошуку хедерів використовується тільки
# консоль, щоб не засмічувати загальні для всіх проектів
# системні шляху, я використовую target_include_directories
# ось посилання, по якій я розібрався з цією командою)
target_include_directories(cpprt
PUBLIC
${EXAMPLE_HIERARCHIES_ROOT}
)

# Линкуем консоль з зібраної бібліотекою cpprt
target_link_libraries(cpprt_console cpprt)

else(CONSOLE_WITH_EXAMPLE)

# Без підключення папки з тестовими ієрархіями -
# все аналогічно збірці simple_example
add_executable(cpprt_console
${CONSOLE_ROOT}/CPPRTConsole.cpp
)
target_link_libraries(cpprt_console cpprt)

endif(CONSOLE_WITH_EXAMPLE)

endif(BUILD_TOOLS)


Консоль зібралася і заробила сходу. Все було готове.

До того часу було (19:23) – суджу по часу, в який я загуглил "м'ятний чай заспокоює".

Результат усієї роботи: конфіг, такий, який зараз використовується в проекті:

CMakeLists.txt#============================================================
# Head
#
cmake_minimum_required(VERSION 2.8.8)

option(BUILD_ALL «Build cpprt tools» OFF)

# Єдиний новий трюк. Заслуговує коментаря.
# Тут як значення за умовчанням для параметру
# передається значення іншої опції. За рахунок цього можна
# встановити однакові значення для цілої групи опцій з
# значення однієї опції, а потім для деяких окремо
# уточнити це значення теж з консолі.
option(BUILD_TOOLS «Build cpprt tools» ${BUILD_ALL})
option(CONSOLE_WITH_EXAMPLE «Add examples to console» ON)

option(BUILD_EXAMPLES «Build cpprt examples» ${BUILD_ALL})

#-----------------------------------------------------------------------------------------------
### — cpprt code
#
project(cpprt_projects)

set(CPPRT_ROOT_PATH .)
set(CPPRT_SOURCES_PATH ${CPPRT_ROOT_PATH}/src)
set(CPPRT_INCLUDE_PATH ${CPPRT_ROOT_PATH}/include)

file(GLOB_RECURSE CPPRT_SOURCES
${CPPRT_SOURCES_PATH}/*.h
${CPPRT_SOURCES_PATH}/*.cpp
)

file(GLOB_RECURSE CPPRT_HEADERS
${CPPRT_INCLUDE_PATH}/*.h
)

include_directories(${CPPRT_INCLUDE_PATH})
add_library(cpprt STATIC ${CPPRT_SOURCES} ${CPPRT_HEADERS})

#- — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — # Global examples setup
#
set(EXAMPLE_HIERARCHIES_ROOT ${CPPRT_ROOT_PATH}/examples/__example_hierarchies__)

file(GLOB_RECURSE EXAMPLE_HIERARCHY_PATHES
${EXAMPLE_HIERARCHIES_ROOT}/*.h
${EXAMPLE_HIERARCHIES_ROOT}/*.cpp
)

#-----------------------------------------------------------------------------------------------
### — Tools
#
if(BUILD_TOOLS)
set(TOOLS_ROOT ${CPPRT_ROOT_PATH}/tools)

#- — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — ### — Console project
set(CONSOLE_ROOT ${TOOLS_ROOT}/console)

if (CONSOLE_WITH_EXAMPLE)
add_executable(cpprt_console
${CONSOLE_ROOT}/CPPRTConsole.cpp
${EXAMPLE_HIERARCHY_PATHES}
)
target_include_directories(cpprt_console
PUBLIC
${EXAMPLE_HIERARCHIES_ROOT}
)
target_link_libraries(cpprt_console cpprt)

else(CONSOLE_WITH_EXAMPLE)
add_executable(cpprt_console
${CONSOLE_ROOT}/CPPRTConsole.cpp
)
target_link_libraries(cpprt_console cpprt)

endif(CONSOLE_WITH_EXAMPLE)

endif(BUILD_TOOLS)

#-----------------------------------------------------------------------------------------------
###- Examples
#
if(BUILD_EXAMPLES)

#- — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — ### — Simple examples
set(SIMPLE_EXAMPLE_ROOT examples/simple_examples)

include_directories(${CPPRT_INCLUDE_PATH})
add_executable(simple_examples
${SIMPLE_EXAMPLE_ROOT}/SimpleExamples.cpp
${CPPRT_SOURCES}
)
target_link_libraries(simple_examples cpprt)
endif(BUILD_EXAMPLES)
#============================================================


Таким чином, я легко і без особливих нервів за чотири години чистого часу розібрався на робочому базовому рівні з утилітою CMake. По-моєму, прилучення до потужними знань CMake стоять чотирьох годин часу.

Закінчуючи, висловлюся з приводу CMake:

Що мені сподобалося:
Потужна утиліта. Вона дійсно знімає необхідність паритися з конфігурацією під купу платформ та компіляторів. Я відчув це, коли після студії згенерував через CMake make-файл для mingw32-make + Eclipse IDE і зібрав исходники через нього так само легко, як до цього збирав те ж саме через Visual Studio.
Що мені не сподобалося:
Дуже дивний дизайн мови. Аргументи з whitespace в якості роздільників, дивний принцип використання іменованих аргументів, не завжди прозорий механізм конфігурування властивостей проектів і цілей складання (іноді властивості задаються глобально для всіх цілей складання, іноді локально для конкретної), дивна політика використання команди (наприклад, команда file насправді поєднує в собі всі операції з файловою системою, а конкретна операція передається з допомогою аргументи команди).

У якісь моменти мені здавалося, що мова для CMake писали інопланетяни: дуже розумні, але мислять трохи не по-нашому.

5. Про документацію



Скажу відразу –мені не вистачило духу скласти англомовну документацію для бібліотеки cpprt. Зараз вся документація зводиться до відсилання читати даний цикл статей, що, мабуть, означає відсутність документації. Я постараюся виправити цей недолік як тільки переведу дух після чотиритижневого марафону, який вилилося написання даного циклу статей.

Не дивлячись на те, що на практиці я не написав доку, я провів деякі теоретичні дослідження з приводу того, на базі чого краще всього робити документацію. Наводжу тут інформацію, яку вдалося знайти. Інформація в основному бралася з цієї статті та коментарів до неї:

WikiВзято з коментаря до статті.

Переваги:
— Вікі зручніше для редагування та читання дизайнерами, художниками, і іншими членами команди, які не є програмістами.
— Вікі задає свої стандарти формування статей. За рахунок цього документацію легше привести до єдиного вигляду.
— Зберігається історія редагувань і є можливість коментування статей.
— Вікі «з коробки» дає можливість пошуку за статтями.
— Вікі просто налаштовувати.

Недоліки:
— Труднощі створення схем у вікі. Я так розумію, під схемами маються на увазі UML, що генеруються з текстових файлів. В коментарях люди писали, що схеми потрібно завантажувати в вікі у вигляді відрендерених картинок. Інші ж згадували плагіни, які дозволяють описати схеми без цих труднощів.
— За твердженням деяких людей, до вікі незручно приробляти роботів. Думаю, під роботами маються на увазі якісь програми для аналізу та/або генерації статей?


GoogleВзяло з цієї коментаря.

Переваги:
— Зручний редактор.
— Доступ звідусіль, командна робота, зберігання версій.
— Расшаріваніє (ридонли і з можливістю редагування).
— Коментування ділянок тексту.
— Вбудовані схеми (з усіма перерахованими вище плюшками).
— Експорт в doc, pdf або публікація у вигляді html.

Недоліки:
— Залежність від сервісів goolge. sistemshik: «Для середньовеликі компаній це рішення неприйнятне просто в силу факту зберігання даних на серверах google».
— Деякі труднощі в прив'язку роботів для роботи з документами. Крім того, як я вже писав, документація частково пишеться роботами. Наскільки просто причепити роботів до googledocs?


DoxygenВікі про Doxygen

На мій погляд, про Doxygen вельми гідно розповідається в цією статтею під авторством Norserium. Єдина претензія до автора: зробивши хороший цикл статей, але не зробив між ними посилання. Ось посилання на останню статтю циклу, на початку якої даються посилання на попередні.

З урахуванням теми даної статті, мене зацікавив ось цей коментар: «В корпоративному середовищі окрему документацію зробити можна, але Doxygen насамперед орієнтований на розробників вільного ПЗ, де дещо інші традиції. Одна справа вставити коментарі в код, і зовсім інше — писати документацію. А адже її ще потрібно підтримувати в актуальному стані»

Переваги:
— Головна перевага це, природно, можливість писати документацію паралельно з кодом. Це підсолоджує пігулку необхідності документування для програмістів, які, як правило, не люблять писати доку — у коді писати доку якось затишніше.
— Підтримка генерації діаграм і latex-формул прямо з коментарів до коду.

Недоліки:
— Поєднання вихідного коду і докладних коментарів для документації дратує деяких програмістів.
— Стиль оформлення документації за замовчуванням декому здається архаїчним, і поміняти його не дуже просто.


Plain textТак. Саме так – документацію ведуть в тому числі у вигляді простого тексту, без яких би то не було інструментів для рендера.

Цитата автора наведеної вище статті: «я веду Документацію переважно текстову. <...> Я люблю текст. Скажу навіть більше, я люблю plaintext. Він швидко набирається і досить виразний». Судячи з коментарів до статті, зберігання доки в Plain text це екзотика і досить поширений спосіб зберігання простий документації.

Переваги:
— Відсутність залежностей від яких би то не було систем рендера, зберігання або генерації документації. Як наслідок — простота додавання в проект і відсутність необхідності установки систем для ведення подібної документації.
— Оповідання без картинок змушує авторів точніше висловлювати свої думки.

Недоліки:
— Часто при документуванні майже неможливо обійтися без діаграм або хоча б без систем посилань. У Plain text все це вставити, ясна річ, не можна.
— Читання документації в такому вигляді може бути не дуже зручно непрограммистам.


Як ви, певно, зрозуміли, після такого первинного ознайомлення з темою документування відкритого ЗА Doxygen виявився поки що фаворитом. Ймовірно, це пов'язано з тим, що я програміст, який любить писати код і не любить сидіти над всякими нудними документами.

Тим не менш, як на мене, одним Doxygen-му хороша документація не обійдеться. Це хороше рішення для ознайомлення з API і, можливо, для відображення якихось простих діаграм. Але часто потрібні більш докладні статті, в деталях описують поведінку коду, з великими і складними малюнками та ілюстраціями крім UML. Це все одно доведеться робити самому, ручками, одними коментарями до исходниками не обійтися.

З приводу документації мені поки що більше нічого сказати. Пишіть – доповню.

6. Про просування бібліотеки



Тут у мене поки немає ніякого досвіду, крім даного циклу статей. Це і є експериментальна спроба просування бібліотеки. Розповісти людям про свій досвід. Подивимося, наскільки це хороший підхід.

Якщо на цю публікацію і на саму бібліотеку буде позитивна реакція читачів, я адаптуються даний цикл статей для англомовної аудиторії і спробую опублікувати де-небудь у них (знаю, є reddit… може, хто-небудь знає ще хороші ресурси?). А там подивимося…

З приводу просування мені поки, мабуть, більше нічого сказати.

7. Висновок

Сподіваюся, мої вишукування, допущені помилки і, головне, чудові коментарі інших людей і внесені завдяки їм правки дозволять тобі, шановний читачу, пройти цей шлях швидше, ніж це зробив я.

Ідея про колективну творчістьЗакінчуючи останню чистову вичитку статті, я згадав запитання, який ставив колись на Тостері. Згадавши його, я подумав: а чому б не зробити колективний доступ до статті. Вона пов'язана зі світом відкритого ПЗ, так чому б не зробити відкритою для редагування саму статтю?

Я викладаю статтю перед публікацією на GitHub, після чого буду вносити зміни у статті на GitHub і коли буде накопичуватися певний масив змін — переносити ці зміни в статтю на хабре (такий собі реліз статті). Якщо знайдуться які-небудь ще коммитеры крім мене і стаття, таким чином, знайде колективне авторство — я був би не проти передати статтю в колективне авторство про відкрите (є такий на хабре?).

Статтю на GitHub я викладаю прямо зараз, але все інше — поки що тільки плани. Пишіть наскільки це буде взагалі відповідати формату хабры і якщо не відповідає — куди має сенс опублікувати статтю для такого принципу роботи над нею?

Посилання на репозиторій


Автор заздалегідь дякує читачам за вказівки на помилки в статті, конструктивні поради та побажання.

ТитриРедагування статті: Сергій Семенякин

Для малювання діаграм було використано онлайн-редактор UML creately.


Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.