Review of the last chapter
In the last chapter, we talked about how to use CMake and a BASH script to conveniently call cmake
in the build/
folder, and some basic commands of CMake. We talked about how to add an executable as the build target, and how to set where to put the binary files and library files.
In this chapter, we will talk about creating libraries with CMake, how to do installation into user-defined directory, and how to output messages from CMake.
Comments in CMake
A #
comments until the end of the line;
A #[[
comments until the next closing brackets ]]
.
Creating libraries with CMake
In anther post of mine, I talked about the differences of the C/C++ static and shared(dynamic) libraries. In this section, we’ll see how to set CMake to make them.
To add a library to the project using the specified source files, use
add_library(<name> [STATIC | SHARED | MODULE]
[EXCLUDE_FROM_ALL]
source1 [source2 ...])
where <name>
is the library target name, this library name needs to be unique in the CMake project. It’s not the library file name. [STATIC | SHARED | MODULE]
(choose one of the 3 options) specifies the library type (see my intro. on the difference, for example).
The default value of the [STATIC | SHARED | MODULE]
option depends on a global CMake variable BUILD_SHARED_LIBS
. If it’s set to ON
, SHARED
will be used; otherwise, STATIC
is the default.
The library will be created in the ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}
(for STATIC
libraries) or the ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
.
CMake Installation
You may be familiar with make install
, which will install the executables and libraries to your system paths (such that you need the admin. privilege to authorize). To be able to enable this with the CMake-generated Makefile, you need to tell CMake to make this rule. A detailed description of all the forms of installation is available at here, but we only show two installation forms in this section as examples.
First one is the installation of TARGETS
. In this mode you specify the target
name you defined in the preceding CMake file that you would like to install to the destination. A common use is
install(TARGETS target_name DESTINATION dir_name)
Remember that the dir_name for DESTINATION
will be preceded by a CMake system variable: ${CMAKE_INSTALL_PREFIX}
, such that the full installation destination is actually ${CMAKE_INSTALL_PREFIX}/dir_name
. This variable is defaulted to be /usr/local
on UNIX and C:/Program Files/
on WINDOWS.
This target_name can be a target you defined for a library file, using add_library
, or executable (runtime) you defined using add_executable
. The install
command will put the target file to the specified DESTINATION
.
CMake Messages
One of the most important things one needs to learn is to print messages on the screen for the user. In CMake, this is done by
message([<mode>] "message to display" ...)
The full description of this command can be found here. In general the message follows the BASH convention, such that the variable expansion is done by ${var}
. For instance, you can print out the system detected C/C++ compilers by
message(STATUS "C compiler is ${CMAKE_C_COMPILER}")
message(STATUS "C++ compiler is ${CMAKE_CXX_COMPILER}")
Examples for this chapter
We will modify and expand our example in the last chapter to reflect the contents in this chapter. First of all, instead of directly build an executable with the source .cpp files, we will compile the Complex.cpp to a shared library first, then link the main program HelloComplex.cpp to the library.
The tree of the directory looks the same as before:
The contents of the CMakeLists.txt are pasted here:
cmake_minimum_required(VERSION 2.6)
project(HelloComplex)
# First of all set up some basic stuff
enable_testing()
set(CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR}/install)
if (APPLE)
cmake_policy(SET CMP0042 NEW)
endif()
if(NOT EXISTS ${PROJECT_SOURCE_DIR}/bin)
file(MAKE_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)
endif()
if(NOT EXISTS ${PROJECT_SOURCE_DIR}/lib)
file(MAKE_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)
endif()
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)
include_directories(${PROJECT_SOURCE_DIR}/include)
add_library(complex SHARED ${PROJECT_SOURCE_DIR}/src/Complex.cpp)
set_property(TARGET complex PROPERTY POSITION_INDEPENDENT_CODE ON)
message(STATUS "The Complex.cpp will be compiled as a shared library")
add_executable(HelloComplex
${PROJECT_SOURCE_DIR}/src/HelloComplex.cpp)
target_link_libraries(HelloComplex complex)
add_test(exeTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/HelloComplex)
install(TARGETS complex DESTINATION lib)
install(TARGETS HelloComplex DESTINATION bin)
Some explanations on the new contents compared to Chapter 1:
set(CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR}/install)
sets the${CMAKE_INSTALL_PREFIX}
to${PROJECT_SOURCE_DIR}/install
, i.e. the install/ folder in the main project folder. If it doesn’t exist, create one. This is what we talked above, about CMake installationcmake_policy(SET CMP0042 NEW)
was specially added for OSX. This gets rid of the warning CMake gives on OSX about shared libraries.add_library(complex SHARED ${PROJECT_SOURCE_DIR}/src/Complex.cpp)
creates a shared library using the Complex.cpp file.set_property(TARGET complex PROPERTY POSITION_INDEPENDENT_CODE ON)
sets the propertyPOSITION_INDEPENDENT_CODE
of targetcomplex
(the library) toON
. This is equivalent to specifying-fPIC
in GNU C/C++ compilers. See my post about C/C++ librariesmessage(STATUS "...")
prints the message on the screen.target_link_libraries(HelloComplex complex)
is self-explanatory: target executableHelloComplex
depends on librarycomplex
install(TARGETS ... DESTINATION ...)
will put the targets (executable and library) to the DESTINATION folders, i.e.${CMAKE_INSTALL_PREFIX}/path_given_by_DESTINATION}
.
The full contents of this chapter can be downloaded through the zipped complete project folder:
cmake_tutorial_chapter2
Frank,
Wrong topic but I couldn’t find a comment section in Migrating Network Solutions email to GSuite. Can I migrate from Network Solutions secretary@mycompany.com to GSuite to secretary@mycompany.com which is an alias of robert@mycompany.com? Assuming I do everything else as directed, since the identical address is an alias email will it transfer the emails?
Hi Robert,
Thanks for the comment. Actually I think in GSuite, an alias is not considered as an account. You probably will have to import the emails to robert@mycompany.com. You can use secretary@mycompany.com as a recipient for receiving emails, but you have to log in through robert@…