CMake configuration for dependencies outside sources dir - c++

I'm working on some basic OpenGL program and want to use CMake for building it.
There are couple of dependencies like glfw, glad, imgui etc...
Currently I have it in a very draft state where everything is just under the sources directory:
./
|____CMakeLists.txt
|____build/
|____include/
| |____KHR/
| |____GLFW/
| |____...
|____lib/
| |____libglfw3.a
| |____...
|____src/
| |____main.cpp
| |____...
| |____vendor/
| | |____imgui/
| | |____glad/
| | |____stb_image/
My CMake config is something like this:
include_directories(${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/src/vendor)
add_executable(${PROJECT_NAME}
src/main.cpp
src/vendor/glad/glad.c src/vendor/glad/glad.h
src/vendor/imgui/...
...
)
target_link_libraries(${PROJECT_NAME} ${PROJECT_SOURCE_DIR}/lib/libglfw3.a)
It all works, but now I want to bring some structure into it.
Mainly I want to have only my code under src.
I hope I'm not going into "XY problem" but I believe my file structure should be like:
./
|____CMakeLists.txt
|____build/
|____include/
|____lib/
|____glad/
| |____CMakeLists.txt
| |____...
|____imgui/
| |____CMakeLists.txt
| |____...
|____...
|____myproject/
| |____CMakeLists.txt
| |____src/
| | |____main.cpp
| | |____...
So that I'll have separate CMake configs for building glad, imgui etc., and then using them to build myproject.
Unfortunately, I'm struggling with understanding CMake documentation. Should I use INTERFACE targets for dependencies? Or how can I tell CMake that imgui must use specific GLFW location?
My main aim is to build myproject. For that I have to also build dependencies. Some dependencies are using other dependencies which I use. For example: I use GLFW and imgui also uses it. Ideally I'd like to be able to have only one place for that. In my case I have it under include and lib in the root of file structure.
Can anyone please share some ideas what could be the CMake config for such case?
What are the best practices?

Related

Conan add local project as dependency

I'm starting to explore Conan package management. So far including dependencies present on the conan center has been trivial, but now I'm struggling including other local dependencies.
Suppose I have the following project structure:
|----Project_A
| |
| |-src
| | |...
| |
| |-CMakeLists.txt
| |-conanfile.txt
|
|----Project_B
| |
| |-src
| | |...
| |
| |-CMakeLists.txt
I want Project_A to have Project_B as dependency. Project_B is already generating static libraries when built.
Is there a way using Conan to add that project as dependency? Meaning that it will build Project_B using the provided CMakeLists file and add it as dependency for Project_A?
Thanks in advance!

CMake Prevent Need for Inclusion of Precise Header Location

I have the following directory structure:
Project
|
|-CMakeLists.txt
Library
|
|-LibProjectA
| |-CMakeLists.txt
| |-src
| |-SomeHeader0.h
|-LibProjectB
| |-CMakeLists.txt
| |-src
| |-SomeHeader1.h
|-LibProjectC
|-CMakeLists.txt
|-src
|-SomeHeader2.h
OpenSourceProject
|
|-CMakeLists.txt
|-src
|-SomeOpenSourceHeader.h
Wherein Project includes the statically linked library LibProjectA in the Library directory. LibProjectA depends on LibProjectB. LibProjectB depends on LibProjectC. LibProjectA, LibProjectB, and LibProjectC all utilize the OpenSourceProject and LibProjectC specifically requires access to SomeOpenSourceHeader.h.
Whenever I perform an add_subdirectory on LibProjectC, I am forced to provide a precise path specifying where SomeOpenSourceHeader.h is. Even if this is in the CMakeLists.txt within the top level Project directory. Is there some way that by merely performing an add_subdirectory on the CMakeLists.txt in the OpenSourceProject, the path can be provided such that files therein can automatically be recognized elsewhere in the code and that the target project doesn't need to have any knowledge about the open source library used at a much lower level.
All libraries are statically linked.

compiler can't find header file on pre-build stage with target_include_directories

Language server (clangd) says he can't find lib.h when I trying to include header in lib_gtests.cpp : #include "lib.h".
But when I compile everything is OK and lib_gtests can find a header file.
I may miss something in CMake or I should use an IDE because they are more "smart" and are able to find these pre-build dependencies
project
|
|-------> src
| |----> main.cpp
| |----> lib
| |----> lib.cpp
| |----> lib.h
|
|
|-------> tests
| |----> lib
| |----> lib_gtests.cpp
|
|
|---->CMakeLists.txt
CMakeLists.txt
add_executable(unit_tests
tests/lib/lib_gtests.cpp
)
target_link_libraries(unit_tests PRIVATE lib)
target_include_directories(unit_tests PRIVATE ${CMAKE_SOURCE_DIR}/src/lib)
sorry for a dumb question, I'm new to C++ and CMake
and sorry for my English in advance
and could I ask for an advice for sources on CMake (not the official docs, they're scary)
use an IDE (it'll make all these included directories on compile stage visible for a language server by itself, I guess this is why everything works fine for me)
or, if you really want to use some text editor with a language server (for instance NeoVim, as I do. Actually, it's such a pain in the butt but I like this) use ccls as a language server and tell CMake to create compile_commands.json file and create a link to this file in your project directory.
cmake -Bbuild -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=YES
ln -s build/compile_commands .

Automake for shared libraries in all subdirectories

I am currently working on a project, that looks like this:
root folder
|---plugin manager
| |---plugin_manager.cpp
| |---plugin_interface.hpp
|
|---libraries
|
|---Plugins
| |
| |---Plugin1
| | |---Plugin1.cpp
| | |---Plugin1.hpp
| |---Plugin2
| | |---Plugin2.cpp
| | |---Plugin2.hpp
I am compiling a .so for each plug-in and then I "load" it with the plugin_manager. This works fine. I even created a simple makefile, which is able to compile a .so. Here are my make and config files:
configure.ac
AC_INIT(My Project, 0.1, my#email, myproject)
AC_PREREQ(2.68)
AC_COPYRIGHT(GNU General Public License)
AM_CONFIG_HEADER([config.h])
AC_CONFIG_MACRO_DIR([m4])
AM_PROG_LIBTOOL
AC_PROG_INSTALL
AC_PROG_CXX
AM_INIT_AUTOMAKE([1.9 foreign])
AC_CONFIG_FILES(Makefile)
AC_ENABLE_SHARED
AC_DISABLE_STATIC
LT_INIT
AC_OUTPUT
Makefile.am
ACLOCAL_AMFLAGS = -I m4
#Generating libtest.so
lib_LTLIBRARIES = libtest.la
#here you can list your source files
libtest_la_SOURCES = Plugin1.cpp
libtest_la_LDFLAGS = -module -avoid-version -export-dynamic
However, this make file is not that user-friendly, since I have to put it manually in each plug-in folder and also change its source files. That is why I want to create another one, which basically by typing make creates an executable in the plugin manager folder, as well as a .so in each plug-in folder. I have been reading for the last couple of days about autotools and tried implementing something similar to what the guys here suggested, but it didn't work. So I hope that there is someone here, who has experience with such makefiles and can give me a tip on how to solve my problem.
Automake has limitations even with wildcards (http://www.gnu.org/software/automake/manual/html_node/Wildcards.html).
I do not thing that to do what you want is possible without using a bash script to generate your Makefile.am.
However, if using CMake is not a problem for you.
You should be able to do it with something like
FILE(GLOB dir_list "${CMAKE_CURRENT_SOURCE_DIR}/Plugins/*")
FOREACH(dir_entry dir_list)
FILE(GLOB file_src "${dir_entry}/*.cpp"
add_library(plugin_${dir_entry} ${file_src})
ENDFOREACH(dir_entry dir_list)

Modular C++ Project Build with CMake

I'm trying to find a way to build a big modular C++ project with CMake.
The structure of the project is the following:
--project_root
--src
--folder_1
--source_1.h
--source_1.cc
--test_source_1.cc // file containing a main with unit tests
--folder_2
--source_2.h
--source_2.cc
--test_source_2.cc // file containing a main with unit tests
--folder_3
...
And so on.
Each folder represent a project module and each module might depend on other modules, so for example source_1.h may include source_2.h.
Every module folder may also contains a test file so the whole project will have multiple executables.
How can I build the whole project with CMake? How should I write my CMakeLists.txt file?
Thank you a lot.
There are many, many examples out there of how to structure CMake projects for C++, many of which are referenced by the tutorial #user2485710 suggested in his comment, so I'm not going to go super in-depth here, but I'll at least give you a good starting point based on the way you want to lay out you folder structure.
The nice thing about CMake is that it can essentially do a tree-decent using the add_subdirectory command. This lets us easily divide up our CMake code to only do what is required at any specific directory level. In otherwords, each CMakeLists.txt file should only do the minimal amount of work needed to properly set up things at the current depth in the directory tree. In you example, your CMake tree might look like this:
--project_root
--src
--CMakeLists.txt
--folder_1
--CMakeLists.txt
--source_1.h
--source_1.cc
--test_source_1.cc // file containing a main with unit tests
--folder_2
--CMakeLists.txt
--source_2.h
--source_2.cc
--test_source_2.cc // file containing a main with unit tests
...
In src/CMakeLists.txt you do all of your project-level initialization, I.E. find_package, setting up your include-path, etc. Then you simply add the following at the end:
add_subdirectory(folder_1)
add_subdirectory(folder_2)
...
This tells CMake that it should look in those folders for additional stuff to do. Now in src/folder_1/CMakeLists.txt, we do the actual work of whatever combination of add_executable and add_library you need to properly build source_1.cc and test_source_1.cc, and likewise in src/folder_2/CMakeLists.txt for source_2.cc, etc.
The other nice thing is that any CMake variables you set higher up the tree are propagated down through add_subdirectory. So, for example, in src/CMakeLists.txt you can check for some sort of 'build unit-test' flag and set the CMake variable there, and then all you have to do in the other CMakeLists.txt files is check for that variable. This can also be super useful to do if you have a project where CMake is dynamically generating header files for you based on checking environment variables for path-names and the like.
If the structure of the project is well-regulated, you could write custom macros or function of cmake to define the modules and their dependencies.
The cmake scripts in OpenCV project is a good reference:
/libs/opencv-2.4.8/sources/
|+cmake/
|+doc/
|~modules/
| |+core/
| | |+doc/
| | |+include/
| | |+perf/
| | |+src/
| | |+test/
| | `-CMakeLists.txt
| |~imgproc/
| | |+doc/
| | |+include/
| | |+perf/
| | |+src/
| | |+test/
| | `-CMakeLists.txt
| |+ml/
| |+...
| |-CMakeLists.txt
|-CMakeLists.txt
root/modules/imgproc/CMakeLists.txt
set(the_description "Image Processing")
ocv_define_module(imgproc opencv_core)
You will need a CMakeLists.txt in each folder where building will occur.
project() is used to set the name of your overall project.
add_subdirectory() is used to command the configuration to process the CMakeLists.txt in that directory.
add_executable() is used to create an executable from included sources.
add_library() is used to create a static or dynamic library that can be added to executables or libraries as a dependency.
Using a build script (.bat, .cmd, or .sh) will allow you to automate some of the cmake process, such as setting up an out-of-source configuration or build.
You should look up the documentation for these commands on the cmake website, https://cmake.org/cmake/help/latest/