Cmake settings to add external c++ classes to a project

Viewed 763

probably a bit of a noob question so bear with me.

What do I want to do? I have a c++ class called main.cpp and with that I want to add the external classes of RtMidi. I can just move the RtMidi classes into the same folder as my main.cpp and include them from there, but it feels a lot cleaner if I can keep them in a sepperate folder.

The RtMidi folder comes with its own Cmake file, and my assumption is that I can build that folder first to create a library that I then can link to. Is this correct? I'm new to c++ and not 100% sure if this is the way you want to add external classes.

When trying to build my project RtMidi is built, but I'm getting a warning that the main.cpp file can't find the include.

I'm building this on a mac with Visual Studio Code and clang as the compiler if that's any help

main.cpp

#include "RtMidi.h"
int main() 
{
    try 
    {
        RtMidiIn midiin;
    } 
    catch (RtMidiError &error) 
    {
        error.printMessage();
    }
    return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.0.0)
project(Music)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

include_directories (Project)
add_subdirectory (lib/rtmidi-4.0.0)

file(GLOB_RECURSE SOURCES RELATIVE ${CMAKE_SOURCE_DIR} "src/*.cpp")
add_executable(Music ${SOURCES})

target_link_libraries(Music RtMidi)

Build output

[main] Building folder: Music 
[main] Configuring folder: Music 
[proc] Executing command: /usr/local/bin/cmake --no-warn-unused-cli -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_C_COMPILER:FILEPATH=/usr/bin/clang -DCMAKE_CXX_COMPILER:FILEPATH=/usr/bin/clang++ -H/Users/username/Code/Music -B/Users/username/Code/Music/build -G "Unix Makefiles"
[cmake] Not searching for unused variables given on the command line.
[cmake] -- Could NOT find PkgConfig (missing: PKG_CONFIG_EXECUTABLE) 
[cmake] CMake Deprecation Warning at lib/rtmidi-4.0.0/CMakeLists.txt:154 (cmake_policy):
[cmake]   The OLD behavior for policy CMP0042 will be removed from a future version
[cmake]   of CMake.
[cmake] 
[cmake]   The cmake-policies(7) manual explains that the OLD behaviors of all
[cmake]   policies are deprecated and that a policy should be set to OLD only under
[cmake]   specific short-term circumstances.  Projects should be ported to the NEW
[cmake]   behavior and not rely on setting a policy to OLD.
[cmake] 
[cmake] 
[cmake] -- Compiling with support for: coremidi
[cmake] -- Configuring done
[cmake] -- Generating done
[cmake] -- Build files have been written to: /Users/username/Code/Music/build
[build] Starting build
[proc] Executing command: /usr/local/bin/cmake --build /Users/username/Code/Music/build --config Debug --target all -- -j 10
[build] Scanning dependencies of target Music
[build] [ 15%] Built target rtmidi
[build] [ 20%] Building CXX object CMakeFiles/Music.dir/src/main.cpp.o
[build] [ 40%] Built target sysextest
[build] [ 40%] Built target qmidiin
[build] [ 50%] Built target apinames
[build] [ 60%] Built target midiout
[build] [ 80%] Built target cmidiin
[build] [ 80%] Built target midiprobe
[build] [ 90%] Built target midiclock
[build] /Users/username/Code/Music/src/main.cpp:5:10: fatal error: 'rtmidi.h' file not found
[build] #include "rtmidi.h"
[build]          ^~~~~~~~~~
[build] 1 error generated.
[build] make[2]: *** [CMakeFiles/Music.dir/src/main.cpp.o] Error 1
[build] make[1]: *** [CMakeFiles/Music.dir/all] Error 2
[build] make: *** [all] Error 2
[build] Build finished with exit code 2

Thankful for any help, and if this is the wrong way to do things, please point me in the correct direction to do this

2 Answers

I can tell that you are new to cmake which is fine. Everyone has to start somewhere.

Basically you aren't getting the proper include directories that your 'Music' needs. And honestly that's not your fault you linked against the 'RtMidi' if they wrote their cmake correctly your project should have compiled.

Here is roughly the code you need (assuming the include directory you are referring to is called inc)

# Where ever that header files resides add it
target_include_directores(Music PRIVATE "lib/rtmidi-4.0.0/.../inc")

====================================================

I'd advise you to read "Professional Cmake: A Practical Guide"

https://crascit.com/professional-cmake/

If you want to learn about writing modern production level cmake. Written by Craig Scott one of cmake's maintainers.

It's how I started learning cmake, and now I get paid to write cmake/C++ for my job.

====================================================

Learning modern cmake is almost impossible online there is so much misinformation.

For example don't glob for your source files:

file(GLOB_RECURSE SOURCES RELATIVE ${CMAKE_SOURCE_DIR} "src/*.cpp")

This will eventually cause problems trust me. But despite that everyone freakin has this in their out of date tutorials.

You want to manually list out both your source/header files and add them using target_sources.

Also don't add include directories like this. This is the old way of doing things which is very bad and can actually hurt compile times.

include_directories (Project)

And I could go on about other bad stuff I can immediately see.

=========================================

If you are thinking that seems overly complex and like it should have been designed better from the beginning. You are right. However the fault isn't cmakes. I'd blame the C/C++ language for not thinking about the build system as part of the language.

Modern cmake is honestly fantastic. We are using it for our production codebase and it's really been fantastic. C++ may not have an official build system, but cmake is basically the closest thing.

Coming a bit late to the party but these problem occured to me today with the same library. So here is my solution for the specific case : Install the RtMidi with these four shell commands

git clone https://github.com/thestk/rtmidi.git rtmidi #get the source code on a folder named rtmidi
cd rtmidi #navigate to the folder
cmake -B build #configure cmake build directory 
cmake --build build  # build the project

The last commands export a library on your pc for cmake to find so the next step is to link it to your project. I just added these lines of code on my cmake

find_package(RtMidi)
target_link_libraries(target_name RtMidi::rtmidi)

That is pretty standard if the cmake of the library you want is correct ,the problem hides on line 182 of rtmidi's cmake target_include_directories(rtmidi PRIVATE These should be replaced with target_include_directories(rtmidi PUBLIC for rtmidi to work correct. This is a known bug on the specific library that should be fixed in the future

Related