CMakeList.txt: 六个例子

我们已经在C++工程的setup提到过,CMake是build system的生成器,它用于生成makefile,然后make就可以使用生成的make file对c++工程进行编译和链接成可执行文件。The make utility and Makefiles provide a build system that can be used to manage the compilation and re-compilation of programs that are written in any programming language. I use Makefiles quite often in my projects to automate the build process; however, there are times when Makefiles become overly complex for the task. Building complex projects is where CMake really shines — CMake is a cross-platform Makefile generator!

本文翻译自Introduction to CMake by Example

以下所有例子都来自该github repo

例子1: The Hello World Example

The first project is contained in the extras/cmake/helloworld文件夹 of the GitHub repo。里面有两个文件: HelloWorld.cpp,CMakeLists.txt。

//HelloWorld.cpp
#include<iostream>
int main(int argc, char *argv[]){
   std::cout << "Hello World!" << std::endl;
   return 0;
}
# CMakeLists.txt
cmake_minimum_required(VERSION 2.8.9)
project (hello)
add_executable(hello helloworld.cpp)
  • The 1st line sets the minimum version of CMake for this project.
  • The 2nd line is the project() command that sets the project name.
  • The 3rd line: the first argument to the add_executable() function is the name of the executable to be built, and the second argument is the source file from which to build the executable.

To build the project, first test that you have CMake installed.

sudo apt-get install cmake
cmake -version

我们就可以build工程了:

cd ~/exploringBB/extras/cmake/helloworld
cmake .
ls

那么这时候看该文件夹,就会多出现4个文件:

  • CMakeCache.txt
  • CMakeFiles
  • Makefile
  • cmake_install.cmake

所以我们发现有了Makefile,那么就可以进一步build:

cd ~/exploringBB/extras/cmake/helloworld
make
./hello

例子2: A Project with Directories

我们来看看一个更复杂的例子

cd ~/exploringBB/extras/cmake/student
tree

这时候我们可以看出该文件夹的tree结构:

我们来看看CMakeLists.txt:

cmake_minimum_required(VERSION 2.8.9)
project(directory_test)

#Bring the headers, such as Student.h into the project
include_directories(include)
 
#you can manually add the sources using the set command:
#set(SOURCES src/mainapp.cpp src/Student.cpp)
 
#However, the file(GLOB...) allows for wildcard additions:
file(GLOB SOURCES "src/*.cpp")
 
add_executable(testStudent ${SOURCES}
  • The include_directories() function is used to bring the header files into the build environment.
  • The set(SOURCES … ) function can be used to set a variable (SOURCES) that contains the name values of all of the source files (.cpp) in the project. However, because each source file must be added manually the next line is used in its place, and this line is commented out.
  • The file() command is used to add the source files to the project. GLOB (or GLOB_RECURSE) is used to create a list of all of the files that meet the globbing expression (i.e., “src/*.cpp“) and add them to a variable SOURCES.
  • The add_executable() function uses the SOURCES variable, rather than an explicit reference to each source file, in order to build the testStudent executable program.

我们想把所有的build相关的file放在build文件夹里,那么我们可以这么做:

cd ~/exploringBB/extras/cmake/student
cd build
cmake ..

这时候build文件夹就会出现跟上一个例子一样的四个build files:

  • CMakeCache.txt
  • CMakeFiles
  • Makefile
  • cmake_install.cmake
cd ~/exploringBB/extras/cmake/student/build
make
#这时在build文件夹下出现了可执行文件,我们可以跑了
./testStudent

这种方法的好处is that all of the files related to the build processare within the build directory. 那么我们可以很容易进行清理他们:

cd ~/exploringBB/extras/cmake/student
rm -r build/*

例子3:Building a Shared Library (.so)

本例子中,我们将例子2中编译成a shared library。整个文件系统完全相同,除了maincpp.cpp被移除了,as it is not relevant to a library build。对应的CMakeLists.txt为:

cmake_minimum_required(VERSION 2.8.9)
project(directory_test)
set(CMAKE_BUILD_TYPE Release)
 
#Bring the headers, such as Student.h into the project
include_directories(include)
 
#However, the file(GLOB...) allows for wildcard additions:
file(GLOB SOURCES "src/*.cpp")
 
#Generate the shared library from the sources
add_library(testStudent SHARED ${SOURCES})
 
#Set the location for library installation 
#-- i.e., /usr/lib in this case
# not really necessary in this example. 
#Use "sudo make install" to apply
install(TARGETS testStudent DESTINATION /usr/lib)
  • The set(CMAKE_BUILD_TYPE Release) function is used to set the build type to be a release build.
  • 之前的 add_executable() function 变成了add_library() function. The library is built as a shared library using the SHARED flag (other options are: STATIC or MODULE) , and the testStudent name is used as the name of the shared library.
  • The last line uses the install() function to define an installation location for the library (in this case it is /usr/lib). Deployment is invoked using a call to sudo make install in this case.

我们打开新的project的文件夹:

cd ~/exploringBB/extras/cmake/studentlib_shared
cd build
cmake ..
make

这时候在build文件夹就有了libtestStudent.so这个liabrary。You can use the ldd command to display the shared library dependencies:

cd ~/exploringBB/extras/cmake/studentlib_shared/build
ls -l *.so
ldd libtestStudent.so

为了让这个shared library可以available system-wide,我们可以add them to the /usr/lib directory,我们可以通过安装libtestStudent.so library来实现:

cd ~/exploringBB/extras/cmake/studentlib_shared/build
sudo make install
#看看能否找到libtestStudent.so
ls -l /usr/lib|grep libtest*

例子4: Building a Static Library (.a)

A statically-linked library is created at compile time to contain all of the code relating to the library — essentially it makes copies of any dependency code, including that in other libraries.

  • This results in a library that is typically larger in size than the equivalent shared library.
  • because all of the dependencies are determined at compile-time, there are fewer run-time loading costs.
  • the library may be more platform-independent.
  • Unless you are certain that you require a static library, you should use a shared library(尽量用share library, 避免用static library)
    1. as there will be fewer code duplications
    2. the shared library can be updated (e.g., for error correction) without recompilation.

the code for example 4 is available in exploringBB/extras/cmake/studentlib_static/ .对应的CMakeLists.txt如下:

cmake_minimum_required(VERSION 2.8.9)
project(directory_test)
set(CMAKE_BUILD_TYPE Release)
 
#Bring the headers, such as Student.h into the project
include_directories(include)
 
#However, the file(GLOB...) allows for wildcard additions:
file(GLOB SOURCES "src/*.cpp")
 
#Generate the static library from the sources
add_library(testStudent STATIC ${SOURCES})
 
#Set the location for library installation -- i.e., /usr/lib in this case
# not really necessary in this example. Use "sudo make install" to apply
install(TARGETS testStudent DESTINATION /usr/lib)
cd ~/exploringBB/extras/cmake/studentlib_static/build/
cmake ..
make
ls -l lib*

例子5:Using a Shared or Static Library(3rd-party library)

这里例子我们将使用例子3中完成的Shared Library (.so),并且我们已经通过make install 将它安装,它是system-wide accessible了。源代码如下:

#include"Student.h"
 
int main(int argc, char *argv[]){
   Student s("Joe");
   s.display();
   return 0;
}

对应的CMakeLists.txt:

cmake_minimum_required(VERSION 2.8.9)
project (TestLibrary)
 
#For the shared library:
set(PROJECT_LINK_LIBS libtestStudent.so )
link_directories( ~/exploringBB/extras/cmake/studentlib_shared/build )
 
#For the static library:
#set(PROJECT_LINK_LIBS libtestStudent.a)
#link_directories( ~/exploringBB/extras/cmake/studentlib_static/build )
 
include_directories(~/exploringBB/extras/cmake/studentlib_shared/include)
 
add_executable(libtest libtest.cpp)
target_link_libraries(libtest ${PROJECT_LINK_LIBS} )

我们需要编译一下

cd ~/exploringBB/extras/cmake/usestudentlib/build
cmake ..
make

例子6:Using multiple 3rd party libraries

1 Comment

Leave a Comment