1

I have for some time had some problems incorporating modern cmake into a project I've been working fr some while and seem to be stuck on how i should define the the individual CMakeLists, and the top-level CMakeList.

My project structure is pretty simple.

├── build
└── src
    ├── include
    │   ├── database
    │   │   ├── database.cpp
    │   │   └── database.h
    │   ├── match
    │   │   ├── match.h
    │   │   └── mathc.cpp
    │   ├── record
    │   │   ├── lib
    │   │   ├── record.cpp
    │   │   └── record.h
    │   └── spectogram
    │       ├── spectogram.cpp
    │       └── spectrogram.h
    └── main.cpp

main.cpp are linked to all the includes, and some of the includes should know the presence of other includes, meaning, I should be able to include match.h in database.h. Some third-party libs are also going to be used, in this case I am using portaudio, download and installed using externalproject_add, which should only be visible for the include which holds the library, in this case record, should only see this.

But how I should define the individual CMakeList, is currently unknown.

I've scouted the net for a proper way of setting this up, but cannot seem to find one that I understand.

How do i define the CMakeLists for this project, and how do i make sure that the includes, are visible for the Main.cpp and the includes files that need them, and how do I make third-party-libraries visible only for the includes that it is being used for.

CMakeLists example structure tried: CMakeLists.txt

cmake_minimum_required(VERSION 3.2)
project(soundcloud)
#add_subdirectory(src/database)
#add_subdirectory(src/match)
#add_subdirectory(src/record)
add_subdirectory(src/include/spectogram)

add_executable(cmakeDemo src/main.cpp)
SET_TARGET_PROPERTIES(cmakeDemo PROPERTIES LINKER_LANGUAGE Cxx)
target_link_libraries(cmakeDemo spectogram)
#target_link_libraries(cmakeDemo database match record spectogram)

src/include/database/CMakeLists.txt

add_library(spectogram STATIC .)
target_include_directories(spectogram PUBLIC .)

getting error message:

CMake Error: Error required internal CMake variable not set, cmake may not be built correctly.
Missing variable is:
CMAKE_Cxx_LINK_EXECUTABLE
CMake Error: Cannot determine link language for target "spectogram".
CMake Error: CMake can not determine linker language for target: spectogram
Lamda
  • 914
  • 3
  • 13
  • 39
  • I would say that your project structure is a rather complicated mess. Why do you have include and src folders inside of each other? What is the point of having separate folder for each header and class? What are actual relations between all these files? Maybe it would be better to reorganize them according to relations between them, that is corresponding to namespace structure of source code? – user7860670 Oct 26 '17 at 10:00
  • you are right.. the include and src within the include folder is redundant... I removed them.. – Lamda Oct 26 '17 at 10:05
  • Maybe this [SO question](https://stackoverflow.com/questions/13521618/c-project-organisation-with-gtest-cmake-and-doxygen) can help you. – oLen Oct 26 '17 at 11:53
  • Hmm... I am not sure if it is understood how I was going to structure this project.. each folder in include, is actually a module with its own purpose. I will first develop each submodule and then put them together in the main. This requires the posibility of make individual submodules only. I am trying to structure it.. – Lamda Oct 26 '17 at 12:35

2 Answers2

1

You can use the PRIVATE property of target_include_directories. When PRIVATE, it means that the include directories will be available to the sources of the target. When PUBLIC, it will also be available to whomever links to the target.

If I were writing this in a single CMakeLists.txt, I'd do this:

cmake_minimum_required(VERSION 3.0)

add_library(database STATIC src/include/database.cpp)
target_include_directories(database PUBLIC src/include/database)

################
add_library(match STATIC src/include/mathc.cpp)
target_include_directories(match PUBLIC src/include/match)

################
include(ExternalProject)
ExternalProject_Add(portAudio ${SomeCommands})

add_library(record STATIC src/include/record.cpp)
target_include_directories(record PUBLIC src/include/record)  # When cmakeDemo links to this, it'll get these includes
target_include_directories(record PRIVATE src/include/record/lib)   # When cmakeDemo links to this, it won't get these includes
target_link_libraries(record portAudio)

#################
add_library(spectogram STATIC src/include/spectogram.cpp)
target_include_directories(spectogram PUBLIC src/include/spectogram)

##################
add_executable(cmakeDemo src/main.cpp)
target_link_libraries(cmakeDemo database match record spectogram)

If I were to do this with distributed CMakeLists.txt, I'd split the files where the ###### lines are, fix the paths, and use add_subdirectory() to include the sub-directories from higher-level cmake files.

Stewart
  • 4,356
  • 2
  • 27
  • 59
  • Sorry for asking a noob question but what about the cmake_minimum_version and the project_name in the other cmakelists? – Lamda Oct 26 '17 at 17:41
  • I seem to be getting error message `CMake Error: Cannot determine link language for target "spectogram". CMake Error: CMake can not determine linker language for target: spectogram` – Lamda Oct 26 '17 at 21:07
  • Yes, you can add a `cmake_minimum_required(VERSION 3.0)` for sure. The `project()` is not really necessary, but is super useful with some IDEs. – Stewart Oct 27 '17 at 17:54
  • I messed up with spectogram. Instead of `add_library(spectogram STATIC src/include/)` it should have been `add_library(spectogram STATIC src/include/spectogram.cpp)`. I've edited the answer. – Stewart Oct 27 '17 at 17:56
0

First, you don't link to includes, you just "include" them during compilation.

Some people put one CMakeList.txt into every directory that contains a fairly independent compilation unit.

Some people just use one big one at the the top.

Having just one CMakeList.txt file makes it easier to start, but if the project gets huge, things get messy.

For every compilation unit, you can specify the include directories with target_include_directories

arved
  • 4,401
  • 4
  • 30
  • 53
  • My intention was also to add one in each directory. But how to define them is the question.. – Lamda Oct 26 '17 at 09:58
  • I am not sure, what you mean with "define". You just create them and include the subdirectory into your cmake project with add_subdirectory – arved Oct 26 '17 at 10:00
  • You can "link to includes" in cmake. It doesn't make much sense when you think about compile-vs-link, but with cmake you "link" to a target. That link will import several properties of the target such as public includes. I totally love your explanation of splitting compilation units. – Stewart Oct 26 '17 at 14:02