Commit eef3e020 authored by Betsy McPhail's avatar Betsy McPhail Committed by Brad King

Help: Populate tutorial guide text

Migrate tutorial text from individual `directions.txt` files to the main
tutorial document.  Add some comments to source code to provide anchors
for inclusion.
parent 862cfc0e
cmake_minimum_required(VERSION 3.3)
project(Tutorial)
set(CMAKE_CXX_STANDARD 14)
# set the version number
set(Tutorial_VERSION_MAJOR 1)
set(Tutorial_VERSION_MINOR 0)
# control where the static and shared libraries are built so that on windows
# we don't need to tinker with the path to run the executable
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_CXX_STANDARD 14)
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
# the version number.
set(Tutorial_VERSION_MAJOR 1)
set(Tutorial_VERSION_MINOR 0)
if(APPLE)
set(CMAKE_INSTALL_RPATH "@executable_path/../lib")
elseif(UNIX)
......
# add the library that runs
add_library(MathFunctions MathFunctions.cxx)
......@@ -62,6 +61,7 @@ target_compile_definitions(MathFunctions PRIVATE "EXPORTING_MYMATH")
set_property(TARGET MathFunctions PROPERTY VERSION "1.0.0")
set_property(TARGET MathFunctions PROPERTY SOVERSION "1")
# install rules
install(TARGETS MathFunctions
DESTINATION lib
EXPORT MathFunctionsTargets)
......
# Import a CMake Project#
This examples shows how a project can find other CMake packages that
generated Config.cmake files.
It also shows how to state a projects external dependencies when generating a Config.cmake.
# Packaging Debug and Release #
By default CMake is model is that a build directory only contains a single
configuration, be it Debug, Release, MinSizeRel, or RelWithDebInfo.
But it is possible to setup CPack to bundle multiple build directories at the same
time to build a package that contains multiple configurations of the same project.
First we need to ahead and construct a directory called 'multi_config' this
will contain all the builds that we want to package together.
Second create a 'debug' and 'release' directory underneath 'multi_config'. At
the end you should have a layout that looks like:
─ multi_config
├── debug
└── release
Now we need to setup debug and release builds, which would roughly entail
the following:
cd debug
cmake -DCMAKE_BUILD_TYPE=Debug ../../MultiPackage/
cmake --build .
cd ../release
cmake -DCMAKE_BUILD_TYPE=Release ../../MultiPackage/
cmake --build .
cd ..
Now that both the debug and release builds are complete we can now use
the custom MultiCPackConfig to package both builds into a single release.
cpack --config ../../MultiPackage/MultiCPackConfig.cmake
Step 0: A Starting Point
Step 1: Configure a File and C++11 Controls
Step 2: Adding a Library
Step 3: Usage Requirements for Library
Step 4: Installing and Testing
Step 5: System Introspection
Step 6: Custom Command and Generated File
Step 7: Building an Installer
Step 8: CDash submission
Step 9: Mixing Static and Shared
Step 10: Generator Expressions
Step 11: Adding Export Configuration
Complete: End result of Step 11
Consumer: Example of Import Packages
MultiPackage: How to package Debug and Release versions
# Adding a Version Number and Configured Header File #
The first feature we will add is to provide our executable and project with a
version number. While we could do this exclusively in the source code, using
CMakeLists provides more flexibility.
To add a version number we modify the CMakeLists file as follows:
cmake_minimum_required(VERSION 3.3)
project(Tutorial)
# the version number.
set(Tutorial_VERSION_MAJOR 1)
set(Tutorial_VERSION_MINOR 0)
# configure a header file to pass some of the CMake settings
# to the source code
configure_file(
"${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
"${PROJECT_BINARY_DIR}/TutorialConfig.h"
)
# add the executable
add_executable(Tutorial tutorial.cxx)
# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
)
We then create a TutorialConfig.h.in file in the source tree with the
following contents:
// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
When CMake configures this header file the values for @Tutorial_VERSION_MAJOR@
and @Tutorial_VERSION_MINOR@ will be replaced by the values from the CMakeLists
file. Next we modify tutorial.cxx to include the configured header file and to
make use of the version numbers. The resulting source code is listed below.
// A simple program that computes the square root of a number
#include <cmath>
#include <iostream>
#include <string>
#include <sstream>
#include "TutorialConfig.h"
int main (int argc, char *argv[])
{
if (argc < 2) {
std::cout << argv[0] << " Version "
<< Tutorial_VERSION_MAJOR << "." << Tutorial_VERSION_MINOR
<< std::endl;
std::cout << "Usage: " << argv[0] << " number" << std::endl;
return 1;
}
double inputValue = atof(argv[1]);
double outputValue = sqrt(inputValue);
std::cout << "The square root of "
<< inputValue << " is " << outputValue << std::endl;
return 0;
}
# Adding C++11 support #
Let's add some C++11 features to our project. We will need to explicitly state
in the CMake code that it should use the correct flags. The easiest way to
enable C++11 support for CMake is by using the CMAKE_CXX_STANDARD
and CMAKE_CXX_STANDARD_REQUIRED variables.
First, replace `atof` with `std::stod` in tutorial.cxx.
Then, add the CMAKE_CXX_STANDARD and CMAKE_CXX_STANDARD_REQUIRED variables to
the CMakeLists file. The STANADARD value should be set to 11, and REQUIRED
should be set to True.
# Build and Test #
Run cmake or cmake-gui to configure the project and then build it with your
chosen build tool
cd to the directory where Tutorial was built (likely the make directory or
a Debug or Release build configuration subdirectory) and run these commands:
Tutorial 4294967296
Tutorial 10
Tutorial
cmake_minimum_required(VERSION 3.3)
project(Tutorial)
set(CMAKE_CXX_STANDARD 14)
# Set the version number
set(Tutorial_VERSION_MAJOR 1)
set(Tutorial_VERSION_MINOR 0)
# control where the static and shared libraries are built so that on windows
# we don't need to tinker with the path to run the executable
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_CXX_STANDARD 14)
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
# the version number.
set(Tutorial_VERSION_MAJOR 1)
set(Tutorial_VERSION_MINOR 0)
# configure a header file to pass the version number only
configure_file(
"${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
......
# add the library that runs
add_library(MathFunctions MathFunctions.cxx)
......@@ -57,5 +56,6 @@ endif()
# building on windows
target_compile_definitions(MathFunctions PRIVATE "EXPORTING_MYMATH")
# install rules
install(TARGETS MathFunctions DESTINATION lib)
install(FILES MathFunctions.h DESTINATION include)
# Adding Generator Expressions #
Generator expressions are evaluated during build system generation to produce
information specific to each build configuration.
Generator expressions are allowed in the context of many target properties, such
as LINK_LIBRARIES, INCLUDE_DIRECTORIES, COMPILE_DEFINITIONS and others. They may
also be used when using commands to populate those properties, such as
target_link_libraries(), target_include_directories(),
target_compile_definitions() and others.
Generator expressions may to used to enable conditional linking, conditional
definitions used when compiling, and conditional include directories and more.
The conditions may be based on the build configuration, target properties,
platform information or any other queryable information.
There are different types of generator expressions including Logical,
Informational, and Output expressions.
Logical expressions are used to create conditional output. The basic expressions
are the 0 and 1 expressions. A "$<0:...>" results in the empty string, and
"$<1:...>" results in the content of "...". They can also be nested.
For example:
if(HAVE_LOG AND HAVE_EXP)
target_compile_definitions(SqrtLibrary
PRIVATE "HAVE_LOG" "HAVE_EXP")
endif()
Can be rewritten with generator expressions:
target_compile_definitions(SqrtLibrary PRIVATE
"$<$<BOOL:${HAVE_LOG}>:HAVE_LOG>"
"$<$<BOOL:${HAVE_EXP}>:HAVE_EXP>"
)
Note that "${HAVE_LOG}" is evaluated at CMake configure time while
"$<$<BOOL:${HAVE_LOG}>:HAVE_LOG>" is evaluated at build system generation time.
......@@ -9,6 +9,7 @@
int main(int argc, char* argv[])
{
if (argc < 2) {
// report version
std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
<< Tutorial_VERSION_MINOR << std::endl;
std::cout << "Usage: " << argv[0] << " number" << std::endl;
......
cmake_minimum_required(VERSION 3.3)
project(Tutorial)
set(CMAKE_CXX_STANDARD 14)
# set the version number
set(Tutorial_VERSION_MAJOR 1)
set(Tutorial_VERSION_MINOR 0)
# control where the static and shared libraries are built so that on windows
# we don't need to tinker with the path to run the executable
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_CXX_STANDARD 14)
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
# the version number.
set(Tutorial_VERSION_MAJOR 1)
set(Tutorial_VERSION_MINOR 0)
# configure a header file to pass the version number only
configure_file(
"${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
......
# add the library that runs
add_library(MathFunctions MathFunctions.cxx)
......@@ -56,5 +55,6 @@ target_compile_definitions(MathFunctions PRIVATE "$<$<BOOL:${USE_MYMATH}>:USE_MY
#building on windows
target_compile_definitions(MathFunctions PRIVATE "EXPORTING_MYMATH")
# install rules
install(TARGETS MathFunctions DESTINATION lib)
install(FILES MathFunctions.h DESTINATION include)
# Adding Export Configuration #
During Step 4 of the tutorial we added the ability for CMake to install the
library and headers of the project. During Step 7 we added the ability
to package up this information so it could be distributed to other people.
The next step is to add the necessary information so that other CMake projects
can use our project, be it from a build directory, a local install or when
packaged.
The first step is to update our install(TARGETS) commands to not only specify
a DESTINATION but also an EXPORT. The EXPORT keyword generates and installs a
CMake file containing code to import all targets listed in the install command
from the installation tree. So let's go ahead and explicitly EXPORT the
MathFunctions library by updating the install command in
MathFunctions/CMakeLists.txt to look like:
install(TARGETS MathFunctions DESTINATION lib EXPORT MathFunctionsTargets)
Now that we have MathFunctions being exported, we also need to explicitly install
the generated MathFunctionsTargets.cmake file. This is done by adding
the following to the bottom of the top-level CMakeLists.txt:
# install the configuration targets
install(EXPORT MathFunctionsTargets
FILE MathFunctionsTargets.cmake
DESTINATION lib/cmake/MathFunctions
)
At this point you should try and run CMake. If everything is setup properly
you will see that CMake will generate an error that looks like:
Target "MathFunctions" INTERFACE_INCLUDE_DIRECTORIES property contains
path:
"/Users/robert/Documents/CMakeClass/Tutorial/Step11/MathFunctions"
which is prefixed in the source directory.
What CMake is trying to say is that during generating the export information
it will export a path that is intrinsically tied to the current machine and
will not be valid on other machines. The solution to this is to update the
MathFunctions target_include_directories to understand that it needs different
INTERFACE locations when being used from within the build directory and from an
install / package. This means converting the target_include_directories
call for MathFunctions to look like:
target_include_directories(MathFunctions
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include>
)
Once this has been updated, we can re-run CMake and see verify that it doesn't
warn anymore.
At this point, we have CMake properly packaging the target information that is
required but we will still need to generate a MathFunctionsConfig.cmake, so
that the CMake find_package command can find our project. So let's go ahead and
add a new file to the top-level of the project called Config.cmake.in with the
following contents:
@PACKAGE_INIT@
include ( "${CMAKE_CURRENT_LIST_DIR}/MathFunctionsTargets.cmake" )
Then, to properly configure and install that file, add the following to the
bottom of the top-level CMakeLists:
include(CMakePackageConfigHelpers)
# generate the config file that is includes the exports
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
INSTALL_DESTINATION "lib/cmake/example"
NO_SET_AND_CHECK_MACRO
NO_CHECK_REQUIRED_COMPONENTS_MACRO
)
# generate the version file for the config file
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
VERSION "${Tutorial_VERSION_MAJOR}.${Tutorial_VERSION_MINOR}"
COMPATIBILITY AnyNewerVersion
)
# install the configuration file
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake
DESTINATION lib/cmake/MathFunctions
)
At this point, we have generated a relocatable CMake Configuration for our project
that can be used after the project has been installed or packaged. If we want
our project to also be used from a build directory we only have to add
the following to the bottom of the top level CMakeLists:
# generate the export targets for the build tree
# needs to be after the install(TARGETS ) command
export(EXPORT MathFunctionsTargets
FILE "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsTargets.cmake"
)
With this export call we now generate a Targets.cmake, allowing the configured
MathFunctionsConfig.cmake in the build directory to be used by other projects,
without needing it to be installed.
......@@ -9,6 +9,7 @@
int main(int argc, char* argv[])
{
if (argc < 2) {
// report version
std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
<< Tutorial_VERSION_MINOR << std::endl;
std::cout << "Usage: " << argv[0] << " number" << std::endl;
......
......@@ -2,7 +2,8 @@ cmake_minimum_required(VERSION 3.3)
project(Tutorial)
set(CMAKE_CXX_STANDARD 14)
# the version number.
# set the version number
set(Tutorial_VERSION_MAJOR 1)
set(Tutorial_VERSION_MINOR 0)
......
# Adding a Library #
Now we will add a library to our project. This library will contain our own
implementation for computing the square root of a number. The executable can
then use this library instead of the standard square root function provided by
the compiler.
For this tutorial we will put the library into a subdirectory
called MathFunctions. It will have the following one line CMakeLists file:
add_library(MathFunctions mysqrt.cxx)
The source file mysqrt.cxx has one function called mysqrt that provides similar
functionality to the compiler’s sqrt function. To make use of the new library
we add an add_subdirectory call in the top-level CMakeLists file so that the
library will get built. We add the new library to the executable, and add the
MathFunctions as an include directory so that mqsqrt.h header file can be
found. The last few lines of the top-level CMakeLists file now look like:
add_subdirectory(MathFunctions)
#add the executable
add_executable(Tutorial tutorial.cxx)
target_link_libraries(Tutorial ${EXTRA_LIBS})
Now let us make the MathFunctions library optional. While for the tutorial
there really isn’t any need to do so, but with larger projects this is a common
occurrence. The first step is to add an option to the top-level CMakeLists file.
option (USE_MYMATH
"Use tutorial provided math implementation" ON)
This will show up in CMake GUI and ccmake with a default value of ON that can
be changed by the user. This setting will be stored so that the user does not
need to set the value each time they run CMake on this build directory.
The next change is to make building and linking the MathFunctions library
conditional. To do this we change the top-level CMakeLists file to look like
the following:
cmake_minimum_required(VERSION 3.3)
project(Tutorial)
set(CMAKE_CXX_STANDARD 14)
# the version number.
set(Tutorial_VERSION_MAJOR 1)
set(Tutorial_VERSION_MINOR 0)
# configure a header file to pass some of the CMake settings
# to the source code
configure_file(
"${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
"${PROJECT_BINARY_DIR}/TutorialConfig.h"
)
# should we use our own math functions
option(USE_MYMATH "Use tutorial provided math implementation" ON)
# add the MathFunctions library?
if(USE_MYMATH)
add_subdirectory(MathFunctions)
list(APPEND EXTRA_LIBS MathFunctions)
list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")
endif(USE_MYMATH)
# add the executable
add_executable(Tutorial tutorial.cxx)
target_link_libraries(Tutorial ${EXTRA_LIBS})
# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
${EXTRA_INCLUDES}
)
Note the use of the variables EXTRA_LIBS, and EXTRA_INCLUDES to collect
up any optional libraries to later be linked into the executable. This is a
classic approach when dealing with many optional components, we will cover the
modern approach in the next step. For now the corresponding changes to the
source code are fairly straightforward and leave us with:
#ifdef USE_MYMATH
double outputValue = mysqrt(inputValue);
#else
double outputValue = sqrt(inputValue);
#endif
Since the source code now requires USE_MYMATH we can add it to the
TutorialConfig.h.in. Simply add the following line:
#cmakedefine USE_MYMATH
Run cmake or cmake-gui to configure the project and then build it with your
chosen build tool and then run the built Tutorial executable.
Which function gives better results, Step1’s sqrt or Step2’s mysqrt?
......@@ -8,6 +8,7 @@
int main(int argc, char* argv[])
{
if (argc < 2) {
// report version
std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
<< Tutorial_VERSION_MINOR << std::endl;
std::cout << "Usage: " << argv[0] << " number" << std::endl;
......
......@@ -6,7 +6,7 @@ set(CMAKE_CXX_STANDARD 14)
# should we use our own math functions
option(USE_MYMATH "Use tutorial provided math implementation" ON)
# the version number.
# set the version number
set(Tutorial_VERSION_MAJOR 1)
set(Tutorial_VERSION_MINOR 0)
......
# Adding Usage Requirements for Library #
Usage requirements allow for far better control over a library / executable's
link and include line. While also giving more control over the transitive
property of targets inside CMake. The primary commands that leverage usage
requirements are:
- target_compile_definitions
- target_compile_options
- target_include_directories
- target_link_libraries
First up is MathFunctions. We first state that anybody linking to MathFunctions
needs to include the current source directory, while MathFunctions itself
doesn't. So this can become an INTERFACE usage requirement.
Remember INTERFACE means things that consumers require but the producer doesn't.
target_include_directories(MathFunctions
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
Now that we've specified usage requirements for MathFunctions we can safely remove
our uses of the EXTRA_INCLUDES variable.
Run cmake or cmake-gui to configure the project and then build it with your
chosen build tool.
......@@ -5,6 +5,7 @@
#include "TutorialConfig.h"
// should we include the MathFunctions header?
#ifdef USE_MYMATH
# include "MathFunctions.h"
#endif
......@@ -12,6 +13,7 @@
int main(int argc, char* argv[])
{
if (argc < 2) {
// report version
std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
<< Tutorial_VERSION_MINOR << std::endl;
std::cout << "Usage: " << argv[0] << " number" << std::endl;
......@@ -20,6 +22,7 @@ int main(int argc, char* argv[])
double inputValue = std::stod(argv[1]);
// which square root function should we use?
#ifdef USE_MYMATH
double outputValue = mysqrt(inputValue);
#else
......
......@@ -6,7 +6,7 @@ set(CMAKE_CXX_STANDARD 14)
# should we use our own math functions
option(USE_MYMATH "Use tutorial provided math implementation" ON)
# the version number.
# set the version number
set(Tutorial_VERSION_MAJOR 1)
set(Tutorial_VERSION_MINOR 0)
......
# Installing and Testing #
Now we can start adding testing support and install rules to our project.
The install rules are fairly simple; for MathFunctions we install the library
and header file, for the application we install the executable and configured
header.
So to MathFunctions/CMakeLists.txt we add:
install (TARGETS MathFunctions DESTINATION bin)
install (FILES MathFunctions.h DESTINATION include)
And the to top-level CMakeLists.txt we add:
install(TARGETS Tutorial DESTINATION bin)
install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
DESTINATION include
)
That is all that is needed to create a basic local install of the tutorial.
Run cmake or cmake-gui to configure the project and then build it with your
chosen build tool. Then build the “install” target by typing 'make install'
from the command line or build the INSTALL target from an IDE. This will
install the appropriate header files, libraries, and executables.
Verify that the installed Tutorial runs. Note: The CMake variable
CMAKE_INSTALL_PREFIX is used to determine the root of where the files will
be installed.
Next let's test our application. Adding testing is an easy process. At the
end of the top-level CMakeLists file we can add a number of basic tests to
verify that the application is working correctly.
# enable testing
enable_testing()
# does the application run
add_test(NAME Runs COMMAND Tutorial 25)
# does the usage message work?
add_test(NAME Usage COMMAND Tutorial)
set_tests_properties(Usage
PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number"
)
# define a function to simplify adding tests
function(do_test target arg result)
add_test(NAME Comp${arg} COMMAND ${target} ${arg})
set_tests_properties(Comp${arg}
PROPERTIES PASS_REGULAR_EXPRESSION ${result}
)
endfunction(do_test)
# do a bunch of result based tests
do_test(Tutorial 25 "25 is 5")
do_test(Tutorial -25 "-25 is [-nan|nan|0]")
do_test(Tutorial 0.0001 "0.0001 is 0.01")
The first test simply verifies that the application runs, does not segfault or
otherwise crash, and has a zero return value. This is the basic form of a CTest
test.
The Usage test uses a regular expression to verify that the usage message
is printed when an incorrect number of arguments are provided.
Lastly, we have a function called do_test that simplifies running the
application and verifying that the computed square root is correct for given
input.
To run tests, cd to the binary directory and run “ctest -N” and “ctest -VV”.
......@@ -5,6 +5,7 @@
#include "TutorialConfig.h"
// should we include the MathFunctions header?
#ifdef USE_MYMATH
# include "MathFunctions.h"
#endif
......@@ -12,6 +13,7 @@
int main(int argc, char* argv[])
{
if (argc < 2) {
// report version
std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
<< Tutorial_VERSION_MINOR << std::endl;
std::cout << "Usage: " << argv[0] << " number" << std::endl;
......@@ -20,6 +22,7 @@ int main(int argc, char* argv[])
double inputValue = std::stod(argv[1]);
// which square root function should we use?
#ifdef USE_MYMATH
double outputValue = mysqrt(inputValue);
#else
......
......@@ -6,7 +6,7 @@ set(CMAKE_CXX_STANDARD 14)
# should we use our own math functions
option(USE_MYMATH "Use tutorial provided math implementation" ON)
# the version number.
# set the version number
set(Tutorial_VERSION_MAJOR 1)
set(Tutorial_VERSION_MINOR 0)
......
......@@ -6,5 +6,6 @@ target_include_directories(MathFunctions
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}