У якості початківця є деякі звичайні назви каталогів, які ви не можете ігнорувати, вони засновані на багаторічній традиції файлової системи Unix. Це:
trunk
├── bin : for all executables (applications)
├── lib : for all other binaries (static and shared libraries (.so or .dll))
├── include : for all header files
├── src : for source files
└── doc : for documentation
Це, мабуть, гарна ідея дотримуватися цього базового планування, принаймні на верхньому рівні.
Щодо розділення файлів заголовків та вихідних файлів (cpp), обидві схеми є досить поширеними. Однак я, як правило, вважаю за краще зберігати їх разом, а щоденні завдання просто практичніше мати файли разом. Крім того, коли весь код знаходиться в одній папці верхнього рівня, тобто trunk/src/
папці, ви можете помітити, що всі інші папки (bin, lib, include, doc і, можливо, деякі тестові папки) на верхньому рівні, на додаток до каталог "build" для збірки з вихідного коду - це всі папки, які не містять нічого, крім файлів, що генеруються в процесі збирання. Таким чином, потрібно створити резервну копію або набагато краще зберігати лише папку src під системою / сервером управління версіями (як Git або SVN).
Що ж стосується встановлення файлів заголовків у системі призначення (якщо ви хочете врешті-решт розповсюдити свою бібліотеку), добре, CMake має команду для встановлення файлів (неявно створює ціль "встановити", робити "зробити встановлення"), який ви можете використовувати для введення всіх заголовків у /usr/include/
каталог. Я просто використовую для цієї мети наступний макрос cmake:
# custom macro to register some headers as target for installation:
# setup_headers("/path/to/header/something.h" "/relative/install/path")
macro(setup_headers HEADER_FILES HEADER_PATH)
foreach(CURRENT_HEADER_FILE ${HEADER_FILES})
install(FILES "${SRCROOT}${CURRENT_HEADER_FILE}" DESTINATION "${INCLUDEROOT}${HEADER_PATH}")
endforeach(CURRENT_HEADER_FILE)
endmacro(setup_headers)
Де SRCROOT
є змінною cmake, яку я встановив у папку src, і INCLUDEROOT
є змінною cmake, яку я налаштовую туди, куди потрібно звертатися до заголовків. Звичайно, є багато інших способів зробити це, і я впевнений, що мій шлях не найкращий. Справа в тому, що немає підстав розділяти заголовки та джерела лише тому, що в цільовій системі потрібно встановлювати лише заголовки, тому що дуже легко, особливо з CMake (або CPack), вибирати та конфігурувати заголовки на встановлюватись, не маючи їх мати в окремому каталозі. І це я бачив у більшості бібліотек.
Цитата: По-друге, я хотів би використовувати рамку тестування Google C ++ для тестування свого коду, оскільки це здається досить простим у використанні. Ви пропонуєте поєднати це з моїм кодом, наприклад, у папці "inc / gtest" або "contrib / gtest"? Якщо ви в комплекті, пропонуєте використовувати скрипт fuse_gtest_files.py, щоб зменшити кількість чи файли або залишити його таким, яким він є? Якщо не в комплекті, як обробляється ця залежність?
Не зв'язуйте залежності зі своєю бібліотекою. Це взагалі досить жахлива ідея, і я завжди ненавиджу її, коли я застрягаю, намагаючись створити бібліотеку, яка це зробила. Це повинно бути вашим останнім засобом, і остерігайтеся підводних каменів. Часто люди поєднують залежності зі своєю бібліотекою або тому, що вони націлені на жахливе середовище розробки (наприклад, Windows), або тому, що вони підтримують лише стару (застарілу) версію бібліотеки (залежності), про яку йдеться. Основна проблема полягає в тому, що ваша пакетна залежність може зіткнутися з уже встановленими версіями тієї самої бібліотеки / програми (наприклад, ви поєднали gtest, але особа, яка намагається створити вашу бібліотеку, вже має нову (або старішу) версію gtest, яка вже встановлена, тоді вони можуть зіткнутися і нанести цій людині дуже неприємний головний біль). Отже, як я вже сказав, робіть це на свій страх і ризик, і я б сказав лише в крайньому випадку. Попросити людей встановити кілька залежностей, перш ніж мати змогу скласти вашу бібліотеку, це набагато менше зла, ніж намагатися вирішити сутички між вашими пакетними залежностями та існуючими установками.
Цитата: Що стосується написання тестів, як вони, як правило, організовані? Я думав мати один файл cpp для кожного класу (наприклад, test_vector3.cpp), але все компільовано в один двійковий файл, щоб їх можна було легко запускати разом?
Один файл cpp на клас (або невелика згуртована група класів та функцій) на мою думку є більш звичним та практичним. Однак, безумовно, не компілюйте їх усіх в один двійковий файл лише для того, щоб "їх можна було працювати разом". Це дійсно погана ідея. Як правило, якщо мова йде про кодування, ви хочете розділити речі настільки, наскільки це розумно зробити. Що стосується одиничних тестів, ви не хочете, щоб один двійковий файл виконував усі тести, тому що це означає, що будь-яка невелика зміна, яку ви внесете до будь-якої вашої бібліотеки, швидше за все, спричинить майже повну перекомпіляцію цієї програми тестування модулів. , і це лише хвилини / години, втрачені в очікуванні перекомпіляції. Просто дотримуйтесь простої схеми: 1 одиниця = 1 одинична програма тестування. Тоді,
Цитата: Оскільки бібліотека gtest, як правило, будується за допомогою cmake і make, я думав, що має сенс мій проект також будуватися таким чином? Якщо я вирішив використовувати наступний макет проекту:
Я б скоріше запропонував цю схему:
trunk
├── bin
├── lib
│ └── project
│ └── libvector3.so
│ └── libvector3.a products of installation / building
├── docs
│ └── Doxyfile
├── include
│ └── project
│ └── vector3.hpp
│_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
│
├── src
│ └── CMakeLists.txt
│ └── Doxyfile.in
│ └── project part of version-control / source-distribution
│ └── CMakeLists.txt
│ └── vector3.hpp
│ └── vector3.cpp
│ └── test
│ └── test_vector3.cpp
│_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
│
├── build
└── test working directories for building / testing
└── test_vector3
Тут можна помітити кілька речей. По-перше, підкаталоги вашого каталогу src повинні відображати підкаталоги вашого каталогу включення, це лише для того, щоб все було інтуїтивно зрозумілим (також намагайтеся тримати структуру підкаталогу досить плоскою (неглибокою), оскільки глибоке вкладання папок. часто більше клопоту, ніж будь-що інше). По-друге, каталог "включати" - це лише інсталяційний каталог, його вміст - це те, що заголовки вибрані з каталогу src.
По-третє, система CMake призначена для поширення по вихідних підкаталогах, а не як один файл CMakeLists.txt на верхньому рівні. Це зберігає речі місцеві, і це добре (у дусі розбиття речей на самостійні частини). Якщо ви додасте нове джерело, новий заголовок або нову програму тестування, все, що вам потрібно, - це відредагувати один невеликий і простий файл CMakeLists.txt у відповідному під-каталозі, не зачіпаючи нічого іншого. Це також дозволяє з легкістю реструктурувати каталоги (CMakeLists є локальними та містяться у переміщених підкаталогах). CMakeLists верхнього рівня повинні містити більшість конфігурацій верхнього рівня, таких як налаштування каталогів призначення, користувацькі команди (або макроси) та пошук пакетів, встановлених у системі. CMakeLists нижнього рівня повинні містити лише прості списки заголовків, джерел,
Цитата: Як повинен виглядати CMakeLists.txt, щоб він міг будувати лише бібліотеку, або бібліотеку, і тести?
Основна відповідь полягає в тому, що CMake дозволяє спеціально виключати певні цілі з "all" (це те, що будується під час введення "make"), а також ви можете створювати конкретні пучки цілей. Я не можу тут зробити підручник CMake, але це досить прямо вперед, щоб дізнатися самостійно. Однак у цьому конкретному випадку рекомендованим рішенням є, звичайно, використання CTest, що є лише додатковим набором команд, які ви можете використовувати у файлах CMakeLists для реєстрації ряду цілей (програм), позначених як одиниця- тести. Отже, CMake помістить усі тести в спеціальну категорію збірок, і саме це ви і попросили, тому вирішена проблема.
Цитата: Також я бачив досить багато проектів, у яких є збірка рекламних файлів і каталог бін. Чи відбувається збірка в каталозі збірки, а потім двійкові файли переміщуються до каталогу бін? Чи будуть бінарні файли для тестів і бібліотека жити там же? Або було б більше сенсу структурувати так:
Мати каталог збірки за межами джерела ("out-of-source" build) - це справді єдине розумне, що потрібно зробити, це фактично стандарт сьогодні. Отож, безумовно, є окремий каталог "build" поза каталогом джерел, як рекомендують люди CMake, і як це робить кожен програміст. Що стосується каталогу бін, то це конвенція, і, мабуть, це гарна ідея дотримуватися цього, як я вже говорив на початку цієї публікації.
Цитата: Я також хотів би використовувати доксиген для документування свого коду. Чи можна змусити це автоматично запускати cmake і make?
Так. Це більш ніж можливо, це приголомшливо. Залежно від того, наскільки фантазії ви хочете отримати, є кілька можливостей. CMake має модуль для Doxygen (тобто find_package(Doxygen)
), який дозволяє реєструвати цілі, які запускатимуть Doxygen у деяких файлах. Якщо ви хочете зробити більш фантазійні речі, такі як оновлення номера версії в Doxyfile або автоматичне введення позначок дати / автора для вихідних файлів тощо, все можливе за допомогою кунг-фу CMake. Як правило, це призведе до того, що ви зберігаєте вихідний Doxyfile (наприклад, "Doxyfile.in", який я помістив у макет папки вгорі), який повинен знаходити лексеми та замінюватися командами розбору CMake. У моєму файлі CMakeLists вищого рівня ви знайдете одну таку частину кунг-фу CMake, яка разом робить кілька фантазійних речей із cmake-doxygen.