1
0
mirror of synced 2024-11-09 22:48:53 +01:00
modern-cmake/chapters/basics/structure.md
2023-03-14 21:33:18 +00:00

65 lines
3.2 KiB
Markdown

# How to structure your project
The following information is biased. But in a good way, I think. I'm going to tell you how to structure the directories in your project. This is based on convention, but will help you:
- Easily read other projects following the same patterns,
- Avoid a pattern that causes conflicts,
- Keep from muddling and complicating your build.
First, this is what your files should look like when you start if your project is creatively called `project`, with a library called `lib`, and a executable called `app`:
```
- project
- .gitignore
- README.md
- LICENSE.md
- CMakeLists.txt
- cmake
- FindSomeLib.cmake
- something_else.cmake
- include
- project
- lib.hpp
- src
- CMakeLists.txt
- lib.cpp
- apps
- CMakeLists.txt
- app.cpp
- tests
- CMakeLists.txt
- testlib.cpp
- docs
- CMakeLists.txt
- extern
- googletest
- scripts
- helper.py
```
The names are not absolute; you'll see contention about `test/` vs. `tests/`, and the application folder may be called something else (or not exist for a library-only project). You'll also sometime see a `python` folder for python bindings, or a `cmake` folder for helper CMake files, like `Find<library>.cmake` files. But the basics are there.
Notice a few things already apparent; the `CMakeLists.txt` files are split up over all source directories, and are not in the include directories. This is because you should be able to copy the contents of the include directory to `/usr/include` or similar directly (except for configuration headers, which I go over in another chapter), and not have any extra files or cause any conflicts. That's also why there is a directory for your project inside the include directory. Use `add_subdirectory` to add a subdirectory containing a `CMakeLists.txt`.
You often want a `cmake` folder, with all of your helper modules. This is where your `Find*.cmake` files go. An set of some common helpers is at [github.com/CLIUtils/cmake](https://github.com/CLIUtils/cmake). To add this folder to your CMake path:
```cmake
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
```
Your `extern` folder should contain git submodules almost exclusively. That way, you can control the version of the dependencies explicitly, but still upgrade easily. See the Testing chapter for an example of adding a submodule.
You should have something like `/build*` in your `.gitignore`, so that users can make build directories in the source directory and use those to build. A few packages prohibit this, but it's much better than doing a true out-of-source build and having to type something different for each package you build.
If you want to avoid the build directory being in a valid source directory, add this near the top of your CMakeLists:
```cmake
### Require out-of-source builds
file(TO_CMAKE_PATH "${PROJECT_BINARY_DIR}/CMakeLists.txt" LOC_PATH)
if(EXISTS "${LOC_PATH}")
message(FATAL_ERROR "You cannot build in a source directory (or any directory with a CMakeLists.txt file). Please make a build subdirectory. Feel free to remove CMakeCache.txt and CMakeFiles.")
endif()
```
See the [extended code example here](https://gitlab.com/CLIUtils/modern-cmake/tree/master/examples/extended-project).