mirror of
https://github.com/ttroy50/cmake-examples.git
synced 2025-12-18 04:14:34 +03:00
= Basic Sub-Project
:toc:
:toc-placement!:
toc::[]
# Introduction
This example shows how to setup a CMake project that includes sub-projects. The
top level CMakeLists.txt calls the CMakeLists.txt in the sub directories to
create the following:
* sublibrary1 - A static library
* sublibrary2 - A header only library
* subbinary - An executable
The files included in this example are:
```
$ tree
.
├── CMakeLists.txt
├── subbinary
│ ├── CMakeLists.txt
│ └── main.cpp
├── sublibrary1
│ ├── CMakeLists.txt
│ ├── include
│ │ └── sublib1
│ │ └── sublib1.h
│ └── src
│ └── sublib1.cpp
└── sublibrary2
├── CMakeLists.txt
└── include
└── sublib2
└── sublib2.h
```
* link:CMakeLists.txt[] - Top level CMakeLists.txt
* link:subbinary/CMakeLists.txt[] - to make the executable
* link:subbinary/main.cpp[] - source for the executable
* link:sublibrary1/CMakeLists.txt[] - to make a static library
* link:sublibrary1/include/sublib1/sublib1.h[]
* link:sublibrary1/src/sublib1.cpp[]
* link:sublibrary2/CMakeLists.txt[] - to setup header only library
* link:sublibrary2/include/sublib2/sublib2.h[]
[TIP]
====
In this example I have moved the header files to a subfolder under each projects +include+
directory, while leaving the target include as the root +include+ folder. This is a good idea to prevent
filename clashes because you have to include a file like below:
[source,cpp]
----
#include "sublib1/sublib1.h"
----
This also means that if you install your library for other users the default install location would be
+/usr/local/include/sublib1/sublib1.h+.
====
# Concepts
## Adding a Sub-Directory
A CMakeLists.txt file can include and call sub-directories which include a CMakeLists.txt
files.
[source,cmake]
----
add_subdirectory(sublibrary1)
add_subdirectory(sublibrary2)
add_subdirectory(subbinary)
----
## Referencing Sub-Project Directories
When a project is created using the `project()` command, CMake will automatically
create a number of variables which can be used to reference details about the project.
These variables can then be used by other sub-projects or the main project. For example,
to reference the source directory for a different project you can use.
[source,cmake]
----
${sublibrary1_SOURCE_DIR}
${sublibrary2_SOURCE_DIR}
----
The variables created by CMake include:
[cols=",",options="header",]
|=======================================================================
|Variable |Info
|PROJECT_NAME | The name of the project set by the current `project()`.
|CMAKE_PROJECT_NAME |the name of the first project set by the `project()`
command, i.e. the top level project.
|PROJECT_SOURCE_DIR |The source director of the current project.
|PROJECT_BINARY_DIR |The build directory for the current project.
|name_SOURCE_DIR | The source directory of the project called "name".
In this example the source directories created would be `sublibrary1_SOURCE_DIR`,
`sublibrary2_SOURCE_DIR`, and `subbinary_SOURCE_DIR`
|name_BINARY_DIR | The binary directory of the project called "name".
In this example the binary directories created would be `sublibrary1_BINARY_DIR`,
`sublibrary2_BINARY_DIR`, and `subbinary_BINARY_DIR`
|=======================================================================
## Header only Libraries
If you have a library that is created as a header only library, cmake supports the +INTERFACE+
target to allow creating a target without any build output. More details can be found from
link:https://cmake.org/cmake/help/v3.4/command/add_library.html#interface-libraries[here]
[source,cmake]
----
add_library(${PROJECT_NAME} INTERFACE)
----
When creating the target you can also include directories for that target using
the +INTERFACE+ scope. The +INTERFACE+ scope is use to make target requirements that are used in any Libraries
that link this target but not in the compilation of the target itself.
[source,cmake]
----
target_include_directories(${PROJECT_NAME}
INTERFACE
${PROJECT_SOURCE_DIR}/include
)
----
## Referencing Libraries from Sub-Projects
If a sub-project creates a library, it can be referenced by other projects by
calling the name of the target in the `target_link_libraries()` command. This
means that you don't have to reference the full path of the new library and it
is added as a dependency.
[source,cmake]
----
target_link_libraries(subbinary
PUBLIC
sublibrary1
)
----
Alternatively, you can create an alias target which allows you to reference the
target in read only contexts.
To create an alias target run:
[source,cmake]
----
add_library(sublibrary2)
add_library(sub::lib2 ALIAS sublibrary2)
----
To reference the alias, just it as follows:
[source,cmake]
----
target_link_libraries(subbinary
sub::lib2
)
----
## Include directories from sub-projects
When adding the libraries from the sub-projects, starting from cmake v3, there is
no need to add the projects include directories in the include directories of the
binary using them.
This is controlled by the scope in the `target_include_directories()` command when creating
the libraries. In this example because the subbinary executable links the sublibrary1
and sublibrary2 libraries it will automatically include the `${sublibrary1_SOURCE_DIR}/include`
and `${sublibrary2_SOURCE_DIR}/include` folders as they are exported with the
+PUBLIC+ and +INTERFACE+ scopes of the libraries.
# Building the example
[source,bash]
----
$ mkdir build
$ cd build/
$ cmake ..
-- The C compiler identification is GNU 4.8.4
-- The CXX compiler identification is GNU 4.8.4
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/matrim/workspace/cmake-examples/02-sub-projects/A-basic/build
$ make
Scanning dependencies of target sublibrary1
[ 50%] Building CXX object sublibrary1/CMakeFiles/sublibrary1.dir/src/sublib1.cpp.o
Linking CXX static library libsublibrary1.a
[ 50%] Built target sublibrary1
Scanning dependencies of target subbinary
[100%] Building CXX object subbinary/CMakeFiles/subbinary.dir/main.cpp.o
Linking CXX executable subbinary
[100%] Built target subbinary
----