Deciding what to write in CMakeLists.txt - mainly in subfolders - c++

I have a simple project going that uses CMake and gtest. I have a basic CMakeLists.txt file working, but I want to get a better understanding of how to use multiple CMakeLists.txt's and connect them. The code so far for the project is like this:
https://github.com/dmonopoly/writeart/tree/10b62048e6eb6a6ddd0658123d85ce4f5f601178
For quicker reference, the only CMakeLists.txt file (in the project root) that I take advantage of has this inside:
cmake_minimum_required(VERSION 2.8)
# Options
option(TEST "Build all tests." OFF) # makes boolean 'TEST' available
# Make PROJECT_SOURCE_DIR, PROJECT_BINARY_DIR, and PROJECT_NAME available
set(PROJECT_NAME MyProject)
project(${PROJECT_NAME})
set(CMAKE_CXX_FLAGS "-g") # -Wall")
#set(COMMON_INCLUDES ${PROJECT_SOURCE_DIR}/include) if you want your own include/ directory
# then you can do include_directories(${COMMON_INCLUDES}) in other cmakelists.txt files
################################
# Normal Libraries & Executables
################################
add_library(standard_lib Standard.cpp Standard.h)
add_library(converter_lib Converter.cpp Converter.h)
add_executable(main Main.cpp)
target_link_libraries(main standard_lib converter_lib)
################################
# Testing
################################
if (TEST)
# This adds another subdirectory, which has project(gtest)
add_subdirectory(lib/gtest-1.6.0)
enable_testing()
# Include the gtest library
# gtest_SOURCE_DIR is available due to project(gtest) above
include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
##############
# Unit Tests
##############
# Naming
set(UNIT_TESTS runUnitTests)
add_executable(${UNIT_TESTS} ConverterTest.cpp)
# standard linking to gtest stuff
target_link_libraries(${UNIT_TESTS} gtest gtest_main)
# extra linking for the project
target_link_libraries(${UNIT_TESTS} standard_lib converter_lib)
# This is so you can do 'make test' to see all your tests run, instead of manually running the executable runUnitTests to see those specific tests.
add_test(NAME myUnitTests COMMAND runUnitTests)
endif()
My goal is to move Standard.cpp and Standard.h into lib/. The moment I do this, though, I find the ordering of what I do in my CMakeLists.txt complicated. I need the library for my gtest setup, but the library would have to get made in lib/CMakeLists.txt, right? Wouldn't it easily become really complicated to find where all your libraries are and executables are as you would have to look through all your CMakeLists.txt's?
If I am missing something conceptually, or if there is a good example I could use to solve this easily, that would be great.
Help appreciated, and thanks in advance.

If you don't want to use multiple CMakeLists.txt files, don't.
################################
# Normal Libraries & Executables
################################
add_library(standard_lib lib/Standard.cpp lib/Standard.h)
add_library(converter_lib lib/Converter.cpp lib/Converter.h)
# Main.cpp needs to know where "Standard.h" is for the #include,
# so we tell it to search this directory too.
include_directories(lib)
If you do want multiple CMakeLists.txt, you'd move it out:
# Main CMakeLists.txt:
add_subdirectory(lib)
include_directories (${standard_lib_SOURCE_DIR}/standard_lib)
link_directories (${standard_lib_BINARY_DIR}/standard_lib)
and in /lib/CMakeLists.txt:
add_library (standard_lib Standard.cpp)
Here's an example.

Related

Export custom library which uses Qt via CMake for use in another CMake project (Windows, Mingw-w64)

A bit of background on what I am trying to achieve: I already have a project that I have developed in CMake (it is collection of CMake projects: basically a state machine with a few helper libraries). Now, I want to develop a GUI in Qt that this state machine can control (and make it do stuff). However, for the life of me, I cannot figure out how to properly export the library which has the Qt classes and functions to another CMake package's executable. I am on Windows, and using the Mingw-w64 compiler and make program.
I was experimenting with 2 simple CMake projects, one which has a simple Qt form (which I just copied from and modified this repository and the corresponding youtube video given in the README), and the other which has the executable. I was trying to link the first project with the second project, however, whenever I build the autogenerated makefile, it fails in the end, saying that symbols are undefined (For example undefined reference to run_stuff::run_stuff()'). I apologize if the files are dirty, I have been trying out various stuff to no avail.
Things I have tried:
I have followed the answer here very carefully.
I have tried setting CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS to ON, as suggested by many sites (like this one) for running DLLs
I have tried making the library static (hence doing away with the need for DLLs)
I have tried setting the target_include_dirs from private to public and also commenting out that line. (not sure what that does, but okay)
However, no matter what I do, I always end with linking errors in the end, and my executable in the second project is not able to access any functions from the Qt project. Any suggestions on what I should try next? Would be really helpful if you could point out errors I am making in my CMakeLists.txt files (once again apologies for the messy code and CMakeLists)
My project CMake file looks like this:
cmake_minimum_required(VERSION 3.14)
# if (WIN32)
# set(CMAKE_SHARED_LIBRARY_PREFIX "")
# endif ()
set(CMAKE_MAKE_PROGRAM $ENV{MAKE})
set(CMAKE_CONFIGURATION_TYPES "Release;RelWithDebInfo" CACHE STRING "" FORCE)
set(CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS ON)
set(WINDOWS_EXPORT_ALL_SYMBOLS ON)
add_subdirectory(QT6CMake)
add_subdirectory(Exec)
The library CMake file:
cmake_minimum_required(VERSION 3.14)
if (WIN32)
project(MY_PROJECT LANGUAGES CXX)
elseif(UNIX)
project(MY_PROJECT)
endif()
set(CMAKE_CONFIGURATION_TYPES "Release;RelWithDebInfo" CACHE STRING "" FORCE)
#======================= INCLUSION OF Qt =======================#
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_PREFIX_PATH $ENV{QTDIR})
find_package(Qt6Core REQUIRED)
find_package(Qt6Widgets REQUIRED)
#=================== INCLUSION OF Project Files ====================#
set(FORMS_DIR "${CMAKE_SOURCE_DIR}/forms")
set(INCLUDE_DIR "${CMAKE_SOURCE_DIR}/include")
set(SOURCE_DIR "${CMAKE_SOURCE_DIR}/src")
include_directories(${FORMS_DIR})
include_directories(${INCLUDE_DIR})
include_directories(${SOURCE_DIR})
file(GLOB_RECURSE SOURCES
"${FORMS_DIR}/*.ui"
"${FORMS_DIR}/*.qrc"
"${INCLUDE_DIR}/*.h"
"${SOURCE_DIR}/*.cpp"
)
#=================== SETUP EXECTUABLE ====================#
# Enable debug logging on RELWITHDEBINFO configuration
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS
$<$<CONFIG:RELWITHDEBINFO>:QT_MESSAGELOGCONTEXT>
)
# Add the forms directory to the AUTOUIC search paths
set(CMAKE_AUTOUIC_SEARCH_PATHS ${CMAKE_AUTOUIC_SEARCH_PATHS} ${FORMS_DIR})
# Add the executable
if (WIN32)
add_executable(MY_PROJECT WIN32 ${SOURCES})
elseif(UNIX)
add_executable(MY_PROJECT ${SOURCES})
endif()
# Add the target includes for MY_PROJECT
target_include_directories(MY_PROJECT PRIVATE ${FORMS_DIR})
target_include_directories(MY_PROJECT PRIVATE ${INCLUDE_DIR})
target_include_directories(MY_PROJECT PRIVATE ${SOURCE_DIR})
#===================== LINKING LIBRARIES =======================#
target_link_libraries(MY_PROJECT Qt6::Widgets)
The Exec CMake file:
cmake_minimum_required(VERSION 3.14)
project(somexec)
add_definitions(${MY_PROJECT_DEFINITIONS})
include_directories(${MY_PROJECT_INCLUDE_DIRS})
if (WIN32)
add_executable(${PROJECT_NAME} WIN32 main.cpp)
elseif(UNIX)
add_executable(${PROJECT_NAME} main.cpp)
endif()
target_link_libraries(${PROJECT_NAME} MY_PROJECT)
Here is the codebase.
EDIT:
Finally the code seems to be working, courtesy of Guillaume Racicot's multiple edits and fixes. I am going to leave this repository public in case anyone wants to see the codebase. Also, right now, I don't understand all the CMake commands that he has used, will try to understand those as well
The CMake code from the tutorial uses very old fashioned and outdated CMake practices. It works when creating a simple project, but won't work when doing libraries. To share files between projects, you need to export the CMake targets. You can do that by creating this file first:
cmake/yourlibrary-config.cmake
include(CMakeFindDependencyMacro)
# write it like you find_package of your cmake scripts
find_dependency(Qt6 COMPONENTS Core Widgets REQUIRED)
include("${CMAKE_CURRENT_LIST_DIR}/yourlibrary-targets.cmake")
Then, add this to your main project cmake files. You should have a CMake file that looks like this:
cmake_minimum_required(VERSION 3.21)
project(yourlibrary CXX)
# First, create your library. List all the files one by one. Don't use globs
add_library(yourlibrary src/mainwindow.cpp)
# Then add an alias of your library to enable target syntax
add_library(yourlibrary::yourlibrary ALIAS yourlibrary)
# Automatically generate Qt ui and moc
set_target_properties(yourlibrary PROPERTIES
AUTOUIC ON
AUTOMOC ON
AUTOUIC_SEARCH_PATHS forms
)
# Then, include gnuinstalldir to get the platform's standard directories:
include(GNUInstallDirs)
# Then, carefully add your include directories. All of your `target_include_directories` must look like this
target_include_directories(yourlibrary PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> # include directory in your build tree
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> # include directory when installed
)
# Then, include Qt and link qt
find_package(Qt6 COMPONENTS Core Widgets REQUIRED)
target_link_libraries(yourlibrary PUBLIC Qt6::Core Qt6::Widgets)
# Now, create the install script. We install all header files under `include/yourlibrary` to install them in `<prefix>/include/yourlibrary`:
install(
DIRECTORY include/yourlibrary
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING PATTERN "*.hpp" PATTERN "*.h"
)
# We add `yourlibrary` target into the export set.
# The export set will contain all targets to be imported by the other project.
# It also installs the library to the install script so they are installed:
install(TARGETS yourlibrary EXPORT yourlibrary-targets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
# Now, we install the export set. This will generate a CMake file exporting all the target for other projects to use:
install(EXPORT yourlibrary-targets
DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/yourlibrary"
NAMESPACE yourlibrary::
)
# Now, we also export the current buildtree. Other project will be able to import the project directly from a build dir:
configure_file(cmake/yourlibrary-config.cmake yourlibrary-config.cmake COPYONLY)
export(
EXPORT yourlibrary-targets
NAMESPACE yourlibrary::
FILE "${PROJECT_BINARY_DIR}/yourlibrary-targets.cmake"
)
# The file we created earlier:
install(
FILES cmake/yourlibrary-config.cmake
DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/yourlibrary"
)
I omitted the installation of the generated headers since they are usually considered private for the project.
For the library, have a source tree looking like this:
yourlibrary
├── cmake
│   └── yourlibrary-config.cmake
├── forms
│   └── mainwindow.ui
├── include
│   └── yourlibrary
│   └── mainwindow.h
├── src
│ └── mainwindow.cpp
└── CMakeLists.txt
To use the library, you have two choices.
Either you embed it in your project using add_subdirectory(yourlibrary)
Either you build it separately and use find_package(yourlibrary REQUIRED)
You can't do both.
I usually prefer using find_package, but it require a package manager to avoid manually building all dependencies.
If you use add_subdirectory
Then remove find_package(yourlibrary REQUIRED) from your project. Simply add the directory and have your main project file look like this:
cmake_minimum_required(VERSION 3.21)
project(exec LANGUAGES CXX)
# Embed the project
add_subdirectory(yourlibrary)
add_executable(myexec main.cpp)
target_link_libraries(myexec PUBLIC yourlibrary::yourlibrary)
I assume a project tree like this:
SampleProject
├── yourlibrary
│ └── ...
├── CMakeLists.txt
└── main.cpp
If you build yourlibrary separately
First, build the library and (optionally) install it in a known location.
Now, you can build your library that uses Qt. You will need a CMakeLists.txt that looks like this:
cmake_minimum_required(VERSION 3.21)
project(myexec LANGUAGES CXX)
# also finds Qt and all
find_package(yourlibrary REQUIRED)
add_executable(myexec main.cpp)
target_link_libraries(myexec PUBLIC yourlibrary::yourlibrary)
If you install the yourlibrary library, it will simply work. If you want to use it from its build tree, simply run the CMake command with -DCMAKE_PREFIX_PATH=/path/to/yourlibrary/build. It should point to the build directory of the library, or the installation prefix if you installed it in a custom location.

How to properly create cmake library for both program and test usage and compile it only once

I have code with one big directory of models which are going to be used in two binaries - the main program and tests. I want to put the models to the library which will compile once and then both main program and tests can use it without recompiling it again.
Here are my current directories:
root/
CMakeLists.cpp
src/
CMakeLists.txt
main.cpp
model/
/*a lot of cpp/hpp files*/
impl/
impl.cpp
impl.hpp (uses models)
test/
CMakeLists.txt
main.cpp
test.cpp (uses models and impl)
root/CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(server)
set(CMAKE_CXX_STANDARD 14)
file(GLOB MODEL_SOURCES "src/model/*.cpp")
add_library(modelLibrary ${MODEL_SOURCES})
add_subdirectory(src)
add_subdirectory(test)
src/CMakeLists.txt
set(BINARY ${CMAKE_PROJECT_NAME})
file(GLOB_RECURSE SOURCES LIST_DIRECTORIES true *.h *.cpp)
set(SOURCES ${SOURCES})
add_executable(${BINARY} ${SOURCES})
include_directories(impl)
# can't see model files without this line
target_include_directories(${BINARY} PRIVATE ./model)
target_link_libraries(${BINARY} PUBLIC modelLibrary pistache pthread ssl crypto)
test/CMakeLists.txt
set(BINARY ${CMAKE_PROJECT_NAME}_test)
file(GLOB_RECURSE TEST_SOURCES LIST_DIRECTORIES false *.hpp *.cpp)
set(SOURCES ${TEST_SOURCES})
add_executable(${BINARY} ${TEST_SOURCES})
add_test(NAME ${BINARY} COMMAND ${BINARY})
# can't see model files without this line
target_include_directories(${BINARY} PRIVATE ../src/model)
target_link_libraries(${BINARY} modelLibrary gtest gtest_main pthread)
I have failed with using modelLibrary as only source. It still compiles the models two times. I'd like to achieve solution where models are compiled once and they are reachable from both - main program and test.
I believe the reason you see the model files compiled twice is due to the recursive glob in src/CMakeLists.txt.
file(GLOB_RECURSE SOURCES LIST_DIRECTORIES true *.h *.cpp)
This recursive glob will also walk into src/model and grab the *.cpp files there. So the model files are getting compiled as part of modelLibrary as well as part of the server executable.
One way to fix this would be to remove the recursive glob and create a separate CMakeLists.txt in src/model with the contents of:
# I wouldn't actually glob, see note below.
file(GLOB MODEL_SOURCES "*.cpp")
add_library(modelLibrary ${MODEL_SOURCES})
target_include_directories(modelLibrary PUBLIC ".")
One would need to make a call add_subdirectory() for this new CMakeLists in either the root or the src/CMakeLists.txt.
Notice the use of target_include_directories in the possible solution. I put that there as I noticed it was being repeated in the test and executable. Using PUBLIC on modelLibrary means that consumers get the include directory just by using target_link_libraries.
Note about globbing: from CMake docs on GLOB
Note We do not recommend using GLOB to collect a list of source files from your source tree. If no CMakeLists.txt file changes when a source is added or removed then the generated build system cannot know when to ask CMake to regenerate. The CONFIGURE_DEPENDS flag may not work reliably on all generators, or if a new generator is added in the future that cannot support it, projects using it will be stuck. Even if CONFIGURE_DEPENDS works reliably, there is still a cost to perform the check on every rebuild.
That note can be a bit hard to grok, but try to fully understand the consequences if you do decide to glob.

Integrating GTest with existing CMake Project: share the same target_sources

I have a large C++ library, and want to do some testing with GTest.
At the moment, the build is handled with CMake, in particular there is one CMakeLists.txt file in the root directory like the following
make_minimum_required(VERSION 3.13.0)
project(mylib)
find_package(PkgConfig REQUIRED)
set(CMAKE_BUILD_WITH_INSTALL_RPATH ON)
set(CMAKE_INSTALL_RPATH "${CMAKE_CURRENT_SOURCE_DIR}/lib/protobuf/src/.libs/")
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
SET(BASEPATH "${CMAKE_SOURCE_DIR}")
INCLUDE_DIRECTORIES("${BASEPATH}")
add_executable(mylib run.cpp)
add_subdirectory(src)
add_subdirectory(proto)
target_include_directories(mylib PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/lib/math
${CMAKE_CURRENT_SOURCE_DIR}/lib/protobuf/src
... some dirs ...
)
target_link_directories(mylib PRIVATE
... some libs ..
)
target_link_libraries(mylib
${CMAKE_CURRENT_SOURCE_DIR}/lib/math
${CMAKE_CURRENT_SOURCE_DIR}/lib/protobuf/src
.....
)
target_compile_options(mylib PUBLIC -D_REENTRANT -fPIC)
Then in the src directory and every sub-directory there is a CMakeLists.txt file, for example this is in src/
target_sources(mylib
PUBLIC
includes.hpp
)
add_subdirectory(algorithms)
add_subdirectory(collectors)
add_subdirectory(hierarchies)
add_subdirectory(mixings)
add_subdirectory(runtime)
add_subdirectory(utils)
My question here is the following: what is the least painful way to integrate GTest in the current project? I was thinking of having a test/ subdirectory, like I've seen here: Adding Googletest To Existing CMake Project
However this example requires that for each executable you manually list all the files it includes. Is there a quicker way to use the sources that are already added to 'mylib'?
You can split the current mylib executable target into two targets
mylib, a library target that is very much like the current mylib target, but without the run.cpp file
mylib_exe an executable target that compiles run.cpp and links to mylib
Now your test files can link to mylib.

gtest setup cmake to get it run

I want to include gtest to my C++ project. I am using Clion as IDE, which should work. Some tests are already working, but I cannot use any functions from B_RocChoice.h. It says that the function is not declared in this scope.
Can somebody tell me what I am doing wrong? How I must change my CMakeLists.txt files that it recogizes my methods?
This is my basic_tests.cpp, where my testcases will be written.
This is my Directory.
Here, the most outer CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(cli)
find_package( OpenCV REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pthread")
set(SOURCE_FILES
include/A_WowbaggerChoice.h
include/AbstractChoice.h
include/B_RocChoice.h
include/C_CnnChoice.h
include/D_DetectorChoice.h
include/E_LearningChoice.h
include/Help.h
include/MyException.h
include/StartScreen.h
include/tinyxml.h
include/types.h
src/A_WowbaggerChoice.cpp
src/AbstractChoice.cpp
src/B_RocChoice.cpp
src/C_CnnChoice.cpp
src/D_DetectorChoice.cpp
src/E_LearningChoice.cpp
src/Help.cpp
src/main.cpp
src/MyException.cpp
src/StartScreen.cpp
tinyxml/tinystr.cpp
tinyxml/tinystr.h
tinyxml/tinyxml.cpp
tinyxml/tinyxml.h)
add_subdirectory(googletest)
add_executable(cli ${SOURCE_FILES})
target_link_libraries( cli ${OpenCV_LIBS} )
CMakeLists.txt for gtest.
cmake_minimum_required(VERSION 2.6.2)
project( googletest-distribution )
enable_testing()
option(BUILD_GTEST "Builds the googletest subproject" ON)
#Note that googlemock target already builds googletest
option(BUILD_GMOCK "Builds the googlemock subproject" OFF)
if(BUILD_GMOCK)
add_subdirectory( googlemock )
elseif(BUILD_GTEST)
add_subdirectory( googletest )
endif()
add_subdirectory(basic_tests)
CMakeLists.txt for basic_tests
include_directories($(gtest_SOURCE_DIR}/include
${getest_SOURCE_DIR}))
#include_directories(../../src/)
include_directories(../../include/)
add_executable(runBasicCli
basic_check.cpp)
target_link_libraries(runBasicCli gtest gtest_main)
#target_link_libraries(cli)
I'm assuming your compiler is complaining it can't find the B_RocChoices.h header? Your question seems to imply the compiler error is about not finding a function, but B_RocChoices is a header and not a function in your basic_tests.cpp file.
Assuming your problem is that the compiler isn't finding the B_RocChoices.h header, I expect that when you include_directories(../../include) you are wanting to make the directory where B_RocChoices.h resides part of the header search path. This is a relative path, so it depends where the compiler is being run from as to what path it means (it wouldn't work if you were doing out of source builds, for example). Try using either CMAKE_SOURCE_DIR or CMAKE_CURRENT_SOURCE_DIR to define the path unambiguously. For example:
include_directories(${CMAKE_SOURCE_DIR}/include)
If you are using CMake 2.8.11 or later, I'd recommend you consider using target_include_directories() instead and probably also read up on target_link_libraries(). Together, these allow you to make the header search paths and linked libraries specific to a target rather than global to all targets. Lastly, if you prefer to download GoogleTest as part of your build rather than embedding it directly in your project sources, you may find the following link useful:
https://crascit.com/2015/07/25/cmake-gtest/

Can I make a library from multiple targets?

I'm trying to learn cmake and have started converting an old make project over to cmake. Here is a simplified version of the directory structure I now have:
CMakeLists.txt
src/
CMakeLists.txt
main.cpp
core/
CMakeLists.txt
/sourcecode, other cmakes, etc.
test/
CMakeLists.txt
someTest.cpp
Currently, in my root CMakeLists.txt file I simply have this:
cmake_minimum_required(VERSION 2.8)
project(all)
add_subdirectory(src)
add_subdirectory(test)
What I wanted to do, was have a library created by core/CMakeLists.txt that can be used by both src/CMakeLists.txt to build the main executable, but also loaded by test/CMakeLists to build the unit tests.
So my src/core/CMakeLists.txt file currently looks sort of like this:
cmake_minimum_required(VERSION 2.8)
project(core)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wpedantic -Wreorder -DBOOST_TEST_DYN_LINK -DBOOST_LOG_DYN_LINK ")
#some other directories in my core code:
add_subdirectory(display)
add_subdirectory(training)
add_subdirectory(utility)
#some packages I use...
find_package(Boost 1.55.0
COMPONENTS
log
program_options
serialization
thread
system
filesystem
REQUIRED)
find_package(GLUT REQUIRED)
find_package(OpenGL REQUIRED)
find_package(Eigen3 REQUIRED)
include_directories(
${PROJECT_SOURCE_DIR}
${EIGEN3_INCLUDE_DIR})
target_link_libraries(core
display
training
utility
${Boost_LIBRARIES}
${OPENGL_LIBRARIES}
${GLUT_LIBRARY}
${OpenMP_LIBRARIES})
So the idea is that I now have a core target I can simply link against to run my tests, and everything should work. However, when I try to build main, for example, I get:
Cannot specify link libraries for target "core" which is not built by this
project.
I thought this might be because core doesn't have a add_library command, but if I add add_library(core) I get this error:
You have called ADD_LIBRARY for library core without any source files. This typically indicates a problem with your CMakeLists.txt file
But I don't want to add any source files; I just want this target to link the targets in the core directory and produce a target I can link against from test.
Clearly I'm missing some core knowledge here, either with cmake or the toolchain itself. Help is appreciated :)
If you only want to create a core target without source files, you need to declare it like an INTERFACE target. So, try to add the following code to your src/core/CMakeLists.txt:
cmake_minimum_required(VERSION 3.0) # REQUIRED 3.x.x version
project(core)
...
# Here declare your core_interface target
add_library(core_interface INTERFACE)
target_link_libraries(core_interface INTERFACE
display
training
utility
${Boost_LIBRARIES}
${OPENGL_LIBRARIES}
${GLUT_LIBRARY}
${OpenMP_LIBRARIES})
As you can see, if you make this, you'll need to upgrade your CMake installed version.
Then, you'll build your tests or any executable, linking with this interface target directly:
add_executable(main main.cpp)
target_link_libraries(main core_interface)