CMake Prevent Need for Inclusion of Precise Header Location - c++

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.

Related

CMake configuration for dependencies outside sources dir

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?

Eclipse CMake support both global project and subprojects

I have a project that I'm trying to configure to make use of CMake, and to make my life easier I'm organizing it as a series of libraries that I'm treating as subprojects.
MyProject
|-- common-cmake
| |-- common-functions1.cmake
| |-- common-functions2.cmake
| `-- CMakeLists.txt
|-- lib1
| |-- include
| | `-- someClass.h
| |-- src
| | `-- someClass.cpp
| |-- test
| | |-- include
| | | `-- someClassTest.h
| | |-- src
| | | `-- someClassTest.cpp
| | `-- CMakeLists.txt
| `-- CMakeLists.txt
|-- lib2
| `-- <snip>
|-- lib3
| `-- <snip>
`-- CMakeLists.txt
There's a global CMakeLists.txt in MyProject that handles the cross-library specifics (such as version information and installation directories) and ensures that everything is included via
add_subdirectory(cmake-common)
add_subdirectory(lib1)
add_subdirectory(lib2)
add_subdirectory(lib3)
common-cmake contains common logic to avoid repetition in each library's or test's CMakeLists.txt (such as common shared library definition since all of the libraries have a common structure). Each library contains a CMakeLists.txt with the necessary information so that it itself can be compiled, and includes its test directory. Each test in turn has its own CMakeLists.txt to provide the necessary details for the compilation of the tests for the library it is contained within. Thus, both the library and its test CMakeLists.txt is dependent on details the global CMakeLists.txt provides and functions that are contained within the common-cmake.
After fighting with the specifics of this, I've got it working. I can kick-off a build from the global level and build/test/install all libraries as well as for an individual library via the appropriate make target.
Now that I've got this working at the global level, I'm trying to get this working in Eclipse. I've managed to get the global project imported and working by calling
cmake -G "Eclipse CDT4 - Unix Makefiles"
at the global level, however this means that everything is contained within a single Eclipse project and I find it extremely unwieldy to work with. Ideally I'd like to have each of the libraries as its own project within Eclipse. I can import the library as a project from within Eclipse directly, but when I do that Eclipse in turn starts throwing errors relating to failure to CMakeCache.txt not existing, or the common functions from common-cmake not being available (since it's not longer starting from the global CMakeLists.txt, those common files are never added).
The only way around this that I can think of would be to allow each library to be both part of the global project (as it is right now) as well as to be usable independently. I've been trying to figure out how this could be done, but unfortunately I haven't had any success.
add_subdirectory("..")
add_subdirectory("../common-cmake")
add_subdirectory doesn't allow me to add anything that's outside of the current directory's subdirectories (which makes a lot of sense), and the only way I've found is to include each file individually and have a rather ugly flag in place to prevent duplication, where the global and the project check each other's flag to prevent stepping on each other's toes.
# Global CMakeLists.txt
add_subdirectory(cmake-common)
if(NOT DEFINED ${PROJECT_BUILD})
set(FULL_BUILD true)
add_subdirectory(lib1)
add_subdirectory(lib2)
add_subdirectory(lib3)
endif()
# lib CMakeLists.txt
if(NOT DEFINED ${FULL_BUILD})
set(PROJECT_BUILD true)
include("../common-cmake/common-functions1.cmake")
include("../common-cmake/common-functions2.cmake")
endif()
Is there a way to accomplish this? Is what I'm trying to do antithetical to CMake and thus not possible? Is there a better way to achieve my end goal?

CMake - Module + Library confusion

I've started a new c++ project , and I am confused with all the CMake capabilities. I have tried to understand better by looking at examples and CMake tutorials
I should create a new project composed of:
Library: It contains some common classes that will be used by the following module(s) (e.g., vector, matrix, image, etc..)
Module (possibly more than 1 in the future): It contains some module-specific classes (e.g., classifier, estimator, etc.) and a main.
My proposed folder structure is as below:
|-- Root Project
|-- CMakeLists.txt
|
|-- Library
| |-- CMakeLists.txt
| |-- include
| | |-- CMakeLists.txt (?)
| | `-- Lib_Class.h
| `-- src
| |-- CMakeLists.txt (?)
| `-- Lib_Class.h
|
|-- Application 1
| |-- CMakeLists.txt
| |-- include
| | |-- CMakeLists.txt (?)
| | `-- Method.h
| `-- src
| |-- CMakeLists.txt (?)
| |-- Method.cpp
| `-- main.cpp
|
|-- Application 2
| |-- CMakeLists.txt
| |
`
The problem arises when I have to actually add the code to the different CMakeLists.txt files. According to my reasoning, I would have:
Root/CMakeLists.txt: For creating the project and adding the subdirectories of the Library and the Module(s).
Library/CMakeLists.txt: This creates the library with the header (from include folder) and source (from src folder) files.
Module/CMakeLists.txt: This creates an executable from the src/main.cpp file using the Library and the module-specific classes with header files in include folder and source files in src folder.
I have 2 questions:
First, I also found solutions in other replies with CMakeLists.txt files in the Library/src and Module/src folders. But I really don't understand how to use them and what to write inside them, because I would have used only the CMakeLists.txt file in the parent folder.
Second, in case I want to link an external library (e.g., OpenCV or dlib) should I link it in the modules and library, individually, or should I link it in the root CMakeLists.txt file (provided that the library is used everywhere)?
I really need some assistance to try to understand CMAKE. Can someone explain or please direct me to a suitable tutorial on this subject.
Matthieu, thank you very much for your help. According to the explanation you provided me, I came out with the following CMakeLists.txt files:
Root/CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(Project_Name)
add_subdirectory(Library)
add_subdirectory(Application)
Library/CMakeLists.txt
project(Library)
set(LIB_HEADERS
include/Lib_Class.h
)
set(LIB_SOURCES
src/Lib_Class.cpp
)
add_library(Library_Name SHARED ${LIB_SOURCES} ${LIB_HEADERS})
Application/CMakeLists.txt
project(Application)
set(APP_HEADERS
include/Method.h
)
set(APP_SOURCES
src/Method.cpp
src/main.cpp
)
add_executable(Application_Name ${APP_SOURCES} ${APP_HEADERS})
target_link_libraries(Application_Name Library_Name)
Now everything seems to work grat! Thank you again and sorry again for being confusing somethimes!
The root cmakelists should set up all the variables, checking compiler support and library presence.
Then you go to each subfolder and create the libraries and executables based on the source code and the detected libraries. You should also set up all the linked libraries there.
Then cmake will figure out what depends on what.

How to get all source files that make up a project in Visual Studio?

For a fairly complex Visual Studio 2013 solution consisting of many large C++ projects, how can I get the paths to all my source code files that end up in my executable for a specific target platform / architecture? This should include the source code from all my projects the application transitively depends on. Example:
Solution
|
+-- Project: Application (depends on "Library A")
| |
| + File: defs.h
| |
| + File: main.cpp
|
+-- Project: Library A (depends on "Library B")
| |
| + File: libA.h
| |
| + File: libA.cpp
|
+-- Project: Library B
|
+ File: libB.h
|
+ File: libB.cpp
In the above, suppose Application depends on Library A, and Library A depends on Library B. When inspecting the Application project, what I'm looking for is the list of paths to the files defs.h, main.cpp, libA.h, libA.cpp, libB.h, libB.cpp.
I'm looking to rely as much as possible on information that is provided by the build tools, like the exact command line that gets passed to the compiler, or some dependency graph. I do not want to write a script that tries to extract all that information from scratch.
Currently, I'm not interested in dependencies to binary / pre-compiled libraries, but only in the source code files that end up in one way or the other in the final executable.

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/