0

I'm writing a C++ library which has the following structure:

my_project
├── include
├── lib
├── src
│   ├── sourceA.cpp
│   └── sourceB.cpp
├── test
│   ├── test.cpp
│   └── CMakeLists.txt
└── CMakeLists.txt

Now I have multiple questions:

  1. How can I layout CMake files in a way so that I can build a test app that uses it from within the library? Here's what I've got so far:

test/CMakeLists.txt

cmake_minimum_required(VERSION 3.12)
project(supabase VERSION 0.2.0.0 LANGUAGES C CXX)
add_subdirectory(..)
add_executable(test test.cpp)
target_link_libraries(test PRIVATE mylib)

MakeLists.txt

add_library(mylib)
target_include_directories(mylib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include");

But CMake complains that

directory "C:/dev/myproject" is not a subdirectory of "C:/dev/myproject/test"

So I could of course create a top level CMakeLists.txt that contains the project information and builds test.cpp. BUT: Of course don't want other developers to build the test routines when they just want to build the lib. Which leads me to question number..

  1. Is there a standardised way to layout the project structure so that it satisfies the following requirements:
  • I can build testscripts from within library and use it at the same time
  • Other devs can just include my top level CMakeLists.txt and build the library without baggage.

What is best practice here?

glades
  • 3,778
  • 1
  • 12
  • 34
  • "So I could of course create a top level `CMakeLists.txt`" - This is not the only way for overcome the error message. Just specify the binary directory as the second argument to `add_subdirectory`, as described in [that question](https://stackoverflow.com/questions/7980784/cmake-add-sub-directory-which-is-not-sub-directory-on-real-directory). "Of course don't want other developers to build the test routines when they just want to build the lib." - You may add a boolean parameter (`option`) for your project, and build the tests only when the parameter is TRUE. – Tsyvarev Oct 20 '22 at 10:34
  • @Tsyvarev Thank you, that should work. However, I have a hard time believing that nothing about project structure is standardized... I find many tutorials on the internet, but every source says something different. Do you know some sample repositories that you consider "exemplary" where I can glean some good practice? – glades Oct 20 '22 at 11:17
  • "I have a hard time believing that nothing about project structure is standardized" - CMake doesn't standardize a project's **structure**. So all "what is the best practice" questions on that topic are mostly *opinion-based*. – Tsyvarev Oct 20 '22 at 11:28
  • @Tsyvarev Given that you have loads more experience with cmake, what is your take? Can you point me to an examplory project? On another note: Is it possible to include CMakeLists.txt with another project() - command specified inside it? – glades Oct 20 '22 at 12:02
  • If you really want to make this according to (at least what I'd consider) best practice, you'd implement logic for installing the library with a cmake configuration file as described here: https://cmake.org/cmake/help/latest/guide/importing-exporting/index.html#importing-targets This would allow you to use something like `find_package(mylib REQUIRED)` in the test cmake; complete test setup: `cmake -S . -B lib_build && cmake --build lib_build && cmake --install lib_build --prefix lib_install && cmake -D "CMAKE_PREFIX_PATH=$(pwd)/lib_install" -S test -B test_build` – fabian Oct 20 '22 at 18:59
  • @fabian Thanks for the input I had a quick look. It looks interesting, however, I wonder how it plays together with git submodules? Are you supposed to avoid submodules and trust the package manager to inform the user that a required package is not found (e.g. with a URL where to download it)? – glades Oct 21 '22 at 06:21
  • I did not consider git submodules at all. My approach would require you to manually check out the submodules using something like `git submodule update --init` before doing anything cmake-related. The FetchContent functionality may work with external repos, but I don't have experience with it. At work we're using find modules that automatically update/init git submodules and use `add_directory` to add the root of the submodule. If you want to go with a specific tag that you're willing to hardcode into your cmake logic, using `FetchContent` is probably the way to go... – fabian Oct 21 '22 at 15:21
  • Please consider whether your multiple questions are [a good idea to go in a single post](https://meta.stackoverflow.com/q/275908/11107541). For the testing question, you can make a `_BUILD_TESTING` `option()`. Also see [`enable_testing()`](https://cmake.org/cmake/help/latest/command/enable_testing.html). – starball Oct 22 '22 at 04:19
  • @fabian I think that's an elegant approach. I want to make my library public and make it work out of the box even for devs not so versed with cmake and git submodules. So to avoid forgetting to init the submodule I could also put the logic in a find module – glades Oct 25 '22 at 09:55

0 Answers0