Introduction
This article provides a straightforward set of “Hello World!” introductions to using CMake for building C++ projects. All steps are performed using Linux on the BeagleBone platform, but the instructions are relevant to most Linux platforms.
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 — particularly when building projects that have multiple sub directories, or projects that are to be deployed to multiple platforms.
Building complex projects is where CMake really shines — CMake is a cross-platform Makefile generator! Simply put, CMake automatically generates the Makefiles for your project. It can do much more than that too (e.g., build MS Visual Studio solutions), but in this discussion I focus on the auto-generation of Makefiles for C/C++ projects.
[tagline_box backgroundcolor=”” shadow=”yes” shadowopacity=”0.7″ border=”0px” bordercolor=”” highlightposition=”top” content_alignment=”left” link=”https://github.com/derekmolloy/exploringBB/tree/master/chp10/cgicc” linktarget=”_blank” modal=”” button_size=”” button_shape=”” button_type=”” buttoncolor=”” button=”Get Source Code” title=”Source Code for this Discussion” description=”” animation_type=”0″ animation_direction=”down” animation_speed=”0.1″ class=”” id=””]
All of the code for this discussion is available in the GitHub repository for the book Exploring BeagleBone. The code can be viewed publicly at: the ExploringBB GitHub CMake Example Projects directory, and/or you can clone the repository on your BeagleBone (or other Linux device) by typing:
1 2 |
molloyd@beaglebone:~$ sudo apt-get install git molloyd@beaglebone:~$ git clone https://github.com/derekmolloy/exploringBB.git |
[/tagline_box]
Example 1: The Hello World Example
The first project is contained in the extras/cmake/helloworld directory of the GitHub repository. In this example a simple “Hello World” C++ program is built (HelloWorld.cpp), which has the source code provided in Listing 1.
1 2 3 4 5 6 |
#include<iostream> int main(int argc, char *argv[]){ std::cout << "Hello World!" << std::endl; return 0; } |
There is only one other file required in the same directory, CMakeLists.txt, which contains the contents of Listing 2.
1 2 3 |
cmake_minimum_required(VERSION 2.8.9) project (hello) add_executable(hello helloworld.cpp) |
The CMakeLists.txt file in Listing 2 consists of only three lines:
- The first line sets the minimum version of CMake for this project, which is major version 2, minor version 8, and patch version 9 in this example. This version is somewhat arbitrary in this example, but providing a version number allows for future support for your build environment. Therefore, you should use the current version of CMake on your system, which for this example is determined just below.
- The second line is the
project()
command that sets the project name. - The third line is the
add_executable()
command, which requests that an executable is to be built using thehelloworld.cpp
source file. The first argument to theadd_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, and if not, install it using the package manager that is used by your flavor of Linux. For example, under Debian:
molloyd@beaglebone:~/$ sudo apt-get install cmake
…
molloyd@beaglebone:~/$ cmake -version
cmake version 2.8.9
The project code is in the GitHub repository directory, where you will see only the two files described in Listings 1 and 2 above:
molloyd@beaglebone:~$ cd ~/exploringBB/extras/cmake/helloworld/
molloyd@beaglebone:~/exploringBB/extras/cmake/helloworld$ ls
CMakeLists.txt helloworld.cpp
Now you are ready to build the Hello World project using CMake — execute the cmake command and pass it the directory that contains the source code and the CMakeLists.txt file — in this case “.
” refers to the current directory:
molloyd@beaglebone:~/exploringBB/extras/cmake/helloworld$ cmake .
-- The C compiler identification is GNU 4.6.3
-- The CXX compiler identification is GNU 4.6.3
-- Check for working C compiler: /usr/bin/gcc
-- Check for working C compiler: /usr/bin/gcc -- 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/molloyd/exploringBB/extras/cmake/helloworld
CMake identified the environment settings for the Linux device and created the Makefile for this project, which can be viewed. Do not make edits to this Makefile, as any edits will be overwritten the next time that the cmake utility is executed.
molloyd@beaglebone:~/exploringBB/extras/cmake/helloworld$ ls
CMakeCache.txt CMakeFiles CMakeLists.txt Makefile cmake_install.cmake helloworld.cpp
molloyd@beaglebone:~/exploringBB/extras/cmake/helloworld$ ls -l Makefile
-rw-r--r-- 1 molloyd molloyd 4811 Apr 1 01:52 Makefile
molloyd@beaglebone:~/exploringBB/extras/cmake/helloworld$ more Makefile
# CMAKE generated file: DO NOT EDIT!
# Generated by "Unix Makefiles" Generator, CMake Version 2.8
…
# The shell in which to execute make rules.
SHELL = /bin/sh
…
Once the Makefile has been created, the make command can be used to build the project:
molloyd@beaglebone:~/exploringBB/extras/cmake/helloworld$ make
Scanning dependencies of target hello
[100%] Building CXX object CMakeFiles/hello.dir/helloworld.cpp.o
Linking CXX executable hello
[100%] Built target hello
molloyd@beaglebone:~/exploringBB/extras/cmake/helloworld$ ls -l hello
-rwxr-xr-x 1 molloyd molloyd 7335 Apr 1 01:54 hello
molloyd@beaglebone:~/exploringBB/extras/cmake/helloworld$ ./hello
Hello World!
It works! However, this process is a somewhat excessive way to just build the HelloWorld.cpp
program. It is important though, because it explains the basic operation of CMake. We can now examine more complex CMake examples.
[separator style_type=”shadow” top_margin=”15″ bottom_margin=”25″ sep_color=”” icon=”” width=”” class=”” id=””]
Example 2: A Project with Directories
As your project grows, it is likely that you will organize it into sub-directories. Makefiles become more verbose when there are sub-directories present — in fact, it is usual practice to place an individual Makefile in each sub-directory. These Makefiles are then individually invoked by the Makefile in the parent directory.
CMake can be very useful in this situation. In this example, a project with a typical directory structure is used. The tree utility program displays below the structure of the example project (note: this student test project is available in the GitHub repository that is described above):
molloyd@beaglebone:~/exploringBB/extras/cmake/student$ tree
.
|-- CMakeLists.txt
|-- build
|-- include
| \-- Student.h
\-- src
|-- Student.cpp
\-- mainapp.cpp
3 directories, 4 files
You can see in this example that any header files (.h) are placed in the include directory and that the source files (.cpp) are placed in the src directory. I have also created a build directory (which is currently empty) that is used to contain the final binary executable and any temporary files that are required for the build. The CMakeLists.txt file for this project in Listing 3 is only slightly different than that in Listing 2 above:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
cmake_minimum_required(VERSION 2.8.9) project(directory_test) #Bring the headers, such as Student.h into the project include_directories(include) #Can manually add the sources using the set command as follows: #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 important changes in Listing 3 are as follows:
- 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
(orGLOB_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 variableSOURCES
. - The
add_executable()
function uses theSOURCES
variable, rather than an explicit reference to each source file, in order to build the testStudent executable program.
For this example, I wish to place all of the build files in the build directory, which is achieved very simply by calling the cmake program from within the build directory, as follows:
molloyd@beaglebone:~/exploringBB/extras/cmake/student$ cd build
molloyd@beaglebone:~/exploringBB/extras/cmake/student/build$ cmake ..
-- The C compiler identification is GNU 4.6.3
-- The CXX compiler identification is GNU 4.6.3
…
-- Build files have been written to: /home/molloyd/exploringBB/extras/cmake/student/build
The build directory then contains the Makefile for the project, which correctly refers to the files in the src and include directories. The project can then be built from the build directory using the make command:
molloyd@beaglebone:~/exploringBB/extras/cmake/student/build$ ls
CMakeCache.txt CMakeFiles Makefile cmake_install.cmake
molloyd@beaglebone:~/exploringBB/extras/cmake/student/build$ make
…
molloyd@beaglebone:~/exploringBB/extras/cmake/student/build$ ls
CMakeCache.txt CMakeFiles Makefile cmake_install.cmake testStudent
molloyd@beaglebone:~/exploringBB/extras/cmake/student/build$ ./testStudent
A student with name Joe
One nice feature of this approach is that all of the files related to the build process are within the build directory as illustrated by the tree utility output below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
molloyd@beaglebone:~/exploringBB/extras/cmake/student/build$ cd .. molloyd@beaglebone:~/exploringBB/extras/cmake/student$ tree . |-- CMakeLists.txt |-- build | |-- CMakeCache.txt | |-- CMakeFiles | | |-- CMakeCCompiler.cmake | | |-- CMakeCXXCompiler.cmake | | |-- CMakeDetermineCompilerABI_C.bin | | |-- CMakeDetermineCompilerABI_CXX.bin | | |-- CMakeDirectoryInformation.cmake | | |-- CMakeOutput.log | | |-- CMakeSystem.cmake | | |-- CMakeTmp | | |-- CompilerIdC | | | |-- CMakeCCompilerId.c | | | `-- a.out | | |-- CompilerIdCXX | | | |-- CMakeCXXCompilerId.cpp | | | `-- a.out | | |-- Makefile.cmake | | |-- Makefile2 | | |-- TargetDirectories.txt | | |-- cmake.check_cache | | |-- progress.marks | | `-- testStudent.dir | | |-- CXX.includecache | | |-- DependInfo.cmake | | |-- build.make | | |-- cmake_clean.cmake | | |-- depend.internal | | |-- depend.make | | |-- flags.make | | |-- link.txt | | |-- progress.make | | `-- src | | |-- Student.cpp.o | | `-- mainapp.cpp.o | |-- Makefile | |-- cmake_install.cmake | `-- testStudent |-- include | `-- Student.h `-- src |-- Student.cpp `-- mainapp.cpp |
To clean this project you can simply recursively delete all files/directories within the build directory, for example:
molloyd@beaglebone:~/exploringBB/extras/cmake/student/build$ cd ..
molloyd@beaglebone:~/exploringBB/extras/cmake/student$ rm -r build/*
molloyd@beaglebone:~/exploringBB/extras/cmake/student$ tree
.
|-- CMakeLists.txt
|-- build
|-- include
| \-- Student.h
\-- src
. |-- Student.cpp
. \-- mainapp.cpp
3 directories, 4 files
which is the same file system structure as was present before the cmake program was executed.
[tagline_box backgroundcolor=”” shadow=”yes” shadowopacity=”0.7″ border=”0px” bordercolor=”” highlightposition=”top” content_alignment=”left” link=”” linktarget=”” modal=”” button_size=”” button_shape=”” button_type=”” buttoncolor=”” button=”” title=”” description=”” animation_type=”0″ animation_direction=”down” animation_speed=”0.1″ class=”” id=””]
Important: If you add new source files to your project it is very important that you call the cmake program again, otherwise the Makefiles will not be updated to account for any additions.
[/tagline_box]
Example 3: Building a Shared Library (.so)
In this example a shared library is built using the project code in Example 2. The project is almost the same, except that the mainapp.cpp file is removed, as it is not relevant to a library build. Therefore, the shared library only contains a single Student class, however, that is sufficient to demonstrate the principles of building a library using CMake. The directory structure of the project is as follows:
molloyd@beaglebone:~/exploringBB/extras/cmake$ tree studentlib_shared/
studentlib_shared/
|-- CMakeLists.txt
|-- build
|-- include
| \-- Student.h
\-- src
. \-- Student.cpp
3 directories, 3 files
Again in this project, header files are placed in the include directory and source files are placed in the src directory. The empty build directory is used to contain the final binary library and any temporary files that are required for the build. The CMakeLists.txt file is provided in Listing 4.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
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 important changes for this example are as follows:
- The
set(CMAKE_BUILD_TYPE Release)
function is used to set the build type to be a release build. - Instead of the
add_executable()
function that is used in previous examples, this example uses theadd_library()
function. The library is built as a shared library using theSHARED
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.
In this example the library is built in the build directory, which results in the output:
molloyd@beaglebone:~/exploringBB/extras/cmake/studentlib_shared$ cd build/
molloyd@beaglebone:~/exploringBB/extras/cmake/studentlib_shared/build$ cmake ..
-- The C compiler identification is GNU 4.6.3
…
molloyd@beaglebone:~/exploringBB/extras/cmake/studentlib_shared/build$ make
Scanning dependencies of target testStudent
[100%] Building CXX object CMakeFiles/testStudent.dir/src/Student.cpp.o
Linking CXX shared library libtestStudent.so
[100%] Built target testStudent
molloyd@beaglebone:~/exploringBB/extras/cmake/studentlib_shared/build$ ls -l *.so
-rwxr-xr-x 1 molloyd molloyd 7503 Apr 1 21:36 libtestStudent.so
You can use the ldd command to display the shared library dependencies:
molloyd@beaglebone:~/exploringBB/extras/cmake/studentlib_shared/build$ ldd libtestStudent.so
libstdc++.so.6 => /usr/lib/arm-linux-gnueabihf/libstdc++.so.6 (0xb6ea6000)
libm.so.6 => /lib/arm-linux-gnueabihf/libm.so.6 (0xb6e3a000)
libgcc_s.so.1 => /lib/arm-linux-gnueabihf/libgcc_s.so.1 (0xb6e16000)
libc.so.6 => /lib/arm-linux-gnueabihf/libc.so.6 (0xb6d31000)
/lib/ld-linux-armhf.so.3 (0xb6f6b000)
The CMakeLists.txt file also includes a deployment step, which allows you to install the library in a suitable accessible location. Shared library locations can be added to the path, or if you wish to make them available system wide you can add them to the /usr/lib directory. For example, the libtestStudent.so library can be installed system wide using:
molloyd@beaglebone:~/exploringBB/extras/cmake/studentlib_shared/build$ sudo make install
[sudo] password for molloyd:
[100%] Built target testStudent
Install the project…
-- Install configuration: "Release"
-- Installing: /usr/lib/libtestStudent.so
molloyd@beaglebone:~/exploringBB/extras/cmake/studentlib_shared/build$ ls -l /usr/lib|grep libtest*
-rw-r--r-- 1 root root 7503 Apr 3 14:23 libtestStudent.so
This step has to be performed with root access in order to write to the /usr/lib directory. You will also find a file in the build directory, called install_manifest.txt that describes the locations at which the make install command applied changes.
[separator style_type=”shadow” top_margin=”15″ bottom_margin=”25″ sep_color=”” icon=”” width=”” class=”” id=””]
Example 4: Building a Static Library (.a)
A statically-linked library is created at compile time to contain all of the code code relating 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, but because all of the dependencies are determined at compile time, there are fewer run-time loading costs and the library may be more platform independent. Unless you are certain that you require a static library, you should use a shared library (Example 3) as there will be fewer code duplications and the shared library can be updated (e.g., for error correction) without recompilation.
To build a static library using CMake, the steps are almost exactly the same as for Example 3 above. The code for this example is available in exploringBB/extras/cmake/studentlib_static/ and the CMakeLists.txt file is provided in Listing 5 below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
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) |
Use the same steps as before to build the static library, and you will see the output as follows:
molloyd@beaglebone:~/exploringBB/extras/cmake/studentlib_static$ cd build/
molloyd@beaglebone:~/exploringBB/extras/cmake/studentlib_static/build$ cmake ..
-- The C compiler identification is GNU 4.6.3
…
molloyd@beaglebone:~/exploringBB/extras/cmake/studentlib_static/build$ make
Scanning dependencies of target testStudent
[100%] Building CXX object CMakeFiles/testStudent.dir/src/Student.cpp.o
Linking CXX static library libtestStudent.a
[100%] Built target testStudent
molloyd@beaglebone:~/exploringBB/extras/cmake/studentlib_static/build$ ls -l lib*
-rw-r--r-- 1 molloyd molloyd 3320 Mar 2 01:50 libtestStudent.a
You can determine the constituents of a static library using the GNU ar (archive) command — for example:
molloyd@beaglebone:~/exploringBB/extras/cmake/studentlib_static/build$ ar -t libtestStudent.a
Student.cpp.o
You can also use the GNU nm command to list the symbols in object files and binaries. In this case, the command lists the symbols in the student library and their types (e.g., T is code, U is undefined, R is read-only data). This information can be very useful for debugging any problems that may occur with static libraries.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
molloyd@beaglebone:~/exploringBB/extras/cmake/studentlib_static/build$ nm -C libtestStudent.a Student.cpp.o: 00000000 b .LANCHOR1 00000000 t _GLOBAL__sub_I__ZN7StudentC2ESs 00000000 T Student::display() 00000060 T Student::Student(std::string) 00000060 T Student::Student(std::string) U std::ctype<char>::_M_widen_init() const U std::ostream::put(char) U std::ostream::flush() U std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&) U std::ios_base::Init::Init() U std::ios_base::Init::~Init() U std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, int) U std::__throw_bad_cast() U std::cout 00000000 b std::__ioinit 00000018 R typeinfo for Student 0000000c R typeinfo name for Student 00000000 R vtable for Student U vtable for __cxxabiv1::__class_type_info U __aeabi_atexit U __aeabi_unwind_cpp_pr0 U __dso_handle |
[separator style_type=”shadow” top_margin=”15″ bottom_margin=”25″ sep_color=”” icon=”” width=”” class=”” id=””]
Example 5: Using a Shared or Static Library
Once a library has been developed using the steps described in Example 3 or Example 4, the next question is how do you use the library in your projects? CMake can be used to generate the Makefiles in your project in order to simplify this process.
Listing 6 provides the source code for a CMakeLists.txt file that can be used to build a program that links to a library (either shared or static). For this example the shared library that is generated in Example 3 is used and a short C++ program is written that utilizes the functionality of that library. This C++ code is provided in Listing 7 and in the directory exploringBB/extras/cmake/usestudentlib/.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
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} ) |
1 2 3 4 5 6 7 |
#include"Student.h" int main(int argc, char *argv[]){ Student s("Joe"); s.display(); return 0; } |
The project can be built and executed using the following steps:
molloyd@beaglebone:~/exploringBB/extras/cmake/usestudentlib$ tree
.
|-- CMakeLists.txt
|-- build
\-- libtest.cpp
1 directory, 2 files
molloyd@beaglebone:~/exploringBB/extras/cmake/usestudentlib$ cd build
molloyd@beaglebone:~/exploringBB/extras/cmake/usestudentlib/build$ cmake ..
-- The C compiler identification is GNU 4.6.3
…
molloyd@beaglebone:~/exploringBB/extras/cmake/usestudentlib/build$ make
Scanning dependencies of target libtest
[100%] Building CXX object CMakeFiles/libtest.dir/libtest.cpp.o
Linking CXX executable libtest
[100%] Built target libtest
molloyd@beaglebone:~/exploringBB/extras/cmake/usestudentlib/build$ ls -l libtest
-rwxr-xr-x 1 molloyd molloyd 7706 Apr 2 21:07 libtest
molloyd@beaglebone:~/exploringBB/extras/cmake/usestudentlib/build$ ./libtest
A student with name Joe
[separator style_type=”shadow” top_margin=”15″ bottom_margin=”25″ sep_color=”” icon=”” width=”” class=”” id=””]
Conclusions
The examples above provide a short and practical introduction to CMake and how it can be used to build: a simple project, a separately compiled project, and a shared library. These are the operations that you are likely to perform and the examples above can act as templates. However, it is also likely that you will require functionality that is not listed in this short discussion. The best, and most up-to-date documentation on CMake is available at the www.cmake.org website. In particular, the CMake Documentation Index provides a very useful list of available commands. The document is available at: CMake 3.0 Documentation Index
Thank you very much. This was very useful 🙂
Thanks! Helped me a lot.
Thanks a lot Derek!! Really helpful.
nice tutorial!!! struglling to get clean and simple understanding of cmakelists from yesterday. your tutorial has just given me what i am looking for. thanks derek 🙂
Your instruction is very easy to follow. Thank you.
Hi,
I am really thankful to you. This is really helpful.
That was fantastic. Absolutely perfect for getting me started with cmake on hierarchical projects that use shared libraries. Thank you!!
Thanks Derek for an excellent walk-through.
thanks a lot, its use ful
Hi Derek,
I’m trying to run the example-5 but received error when executed make command.
/home/user/exploringBB/extras/cmake/usestudentlib/libtest.cpp:1:20: fatal error: Student.h: No such file or directory
#include”Student.h”
^
compilation terminated.
make[2]: *** [CMakeFiles/libtest.dir/libtest.cpp.o] Error 1
make[1]: *** [CMakeFiles/libtest.dir/all] Error 2
make: *** [all] Error 2
Can you help me to figure out what I’m missing?
Thanks,
Hi Pankaj,
To solve the fatal error problem you need to give complete path where the header is available.
In CMakeLists.txt file,
link_directories(/home/lakshminadh/nadh/myCMake/exploringBB/extras/cmake/studentlib_shared/build )
include_directories(/home/lakshminadh/nadh/myCMake/exploringBB/extras/cmake/studentlib_shared/include)
instead of
link_directories(~/exploringBB/extras/cmake/studentlib_shared/build )
include_directories(~/exploringBB/extras/cmake/studentlib_shared/include)
This solution will solve your issue. Let me know whether this solution works for you or not.
Thank you. with full address, it works for static library. however, it doesn’t still work for shared library. The error statement reads ” cannot find -llibtestStudent.so”. Can you please help me with this issue? I am using cygwin for windows.
Awesome intro to CMake; had me up and running in no time!
Give this man a cookie 🙂 The best write up on cmake
Nice Tutorial..!!!! Helped a lot to understand basic concept and example about cmake command.
The best source to get started with cmake. Thank you for a really wonderful article.
Very Nice tutorial thank you.
I was wondering, how do i precise the c++ version i’m using? for example c++ 11.
Thanks again.
Thanks, it’s very helpful tutorials.
Very useful tutorial
Thank you, this helped quite a bit!
Thanks a lot. Very nicely explained. Essential for the beginners.
Very nice…Thanks
Everything else I’ve seen seems needlessly complicated. People look for a build system to make it simpler. A complete compiler call is a lot of typing in all but the most trivial examples. You have delivered a necessary service.
I was reading two other instructions for getting started with CMAKE. Yours had by far the most useful use cases and was the easiest to follow. Thank you very much.
Really nice tutorial! Thank you so much!
Great Post!! Simple and Precise!! (y)
I was wondering if you could extend this post and also include how to build a visual studio project/solution via command line.
Would be very helpful.
Thanks.
Very Useful. Thanks.
Excellent tutorial on CMake basics that helped me do exactly what I needed.
Thank you so much!!
Very helpful and easy to understand!
Linking an existing static library (commented out in the example) does not seem to work. The linker is not able to find the library regardless of the specified link_directories.
Great tutorial, thanks a lot!
Excellent tutorial! Thank you!
Have been following your blogs for years now. From being a student to a professional I still follow them many times as references. Keep up the awesome work, sir!
Great tutorial! It was really well explained. How about a part 2? I would like to know how to use cmake for a project with multiple modules or subdirectories. And then each subdirectory would create a shared library where a main program would link to. The main program would reside in the same project as the shared libraries.
It is very usefull.Now I understood about cmake.thanks.I already contacted you through the mail.I have been following from past one years.
Great tutorial! Simply explained! Thank you.
Thanks for this great introduction!
I could not get the cmake .. to use build dir for the build files
molloyd@beaglebone:~/exploringBB/extras/cmake/student$ cd build
molloyd@beaglebone:~/exploringBB/extras/cmake/student/build$ cmake ..
— The C compiler identification is GNU 4.6.3
— The CXX compiler identification is GNU 4.6.3
…
— Build files have been written to: /home/molloyd/exploringBB/extras/cmake/student/
Same issue I dont know what to do.
Great tutorial, excellent explanation. Thank you very much.
So great ! Thank you.
Just another fan of this post wanting to say I really appreciate your exposition! This will help me with creating a shared library with CMake, which is my current task at my company. Thanks a bunch 🙂
Hey I tried the second example and it wouldnt work. It just prints out a list of options and setting for cmake. Am I missing something.
You probably did just “cmake” and not “cmake .”
Not that cmake is hard to understand , but for a beginner like me , was hard to find even understand the basic stuff mentioned in most of the site. Dr.Derek Molloy Thanks a ton for sucha user friendly and simple tutorial !
It helped me a lot .
Great material.
Thanks for the help
Thanks for this! Have a question about the part about using the library: I followed the instructions and have an include, src, build and all the files. When doing “make”, I get the following message: /usr/bin/ld: cannot find -ltestStudent. What does this mean? Thank you!
straight to the point tutorial. thank you for sharing.
Hi, thanks for the useful tutorial, the only nit is that the install portion of the shared library, should also install the header file in something like /usr/include or /usr/local/include.
I added this line to the CMakeLists.txt in example 5:
install(FILES “${PROJECT_SOURCE_DIR}/include/Student.h” DESTINATION include)
and now running make install gives:
$ sudo make install
[100%] Built target testStudent
Install the project…
— Install configuration: “Release”
— Up-to-date: /usr/lib/libtestStudent.so
— Installing: /usr/local/include/Student.h
Other than that, things work fine.
Just starting to learn how to use VTK and cmake is required. This post is just perfect. Thank you.
Best example I’ve seen last time
Thank you Derek. Great material.
Hi,
I really appreciate your efforts. It perfectly worked for me. Exception is, you did not give explanation of last CMakeLists.txt file. It would be great for future is could add.
This is f***in awesome bro !
Helped me a lot
Very nice, thanks!
When I play with the examples on my desktop Fedora 25 I get the following error:
/usr/bin/ld: skipping incompatible [somedir]/exploringBB/extras/cmake/studentlib_shared/build/libtestStudent.so when searching for -ltestStudent
/usr/bin/ld: cannot find -ltestStudent
collect2: error: ld returned 1 exit status
What might be wrong? Thanks!
Thank you, neat tutorial!
Sir,
Could you please give a similar tutorial for cross compiling for android using cmake on linux (host).
Thanks in advance.
Cheers!!! Great Tutorial!!!
Thanks. You make life easier.
awesome, thanks!
Best example for beginners!
Thank you!
perfect example! thank you!
Fantastik Explanation. Easy to understand. Thanks a lot..
Thankyou for this, as simple as useful, tutorial.
Lore
Thank you so much! This is the best introductory tutorial I ever seen.
Thank you sir, this post helps a lot!
Hi, I have been trying to understand CMake for a long time…But this tutorial has solved all the basic doubts for once and for All…Thank You very much for a great tutorial..
Does this example work for windows also…i.e. does it produces .dll and .lib files with this same cmake script?
In windows (anaconda shell here) my building and compilation steps were slightly different:
cmake -S FILEPATHMAKEFILE -B FILEPATHMAKEFILE/build
cmake –build build
For me this all worked for a STATIC library. Unfortunately I did not get it running with a SHARED library since the compiled *.exe kept complaining about the missing dll, which clearly existed though (set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) in the makefile during SHARED library creation as hinted at in https://stackoverflow.com/questions/40739061/error-lnk1104-cannot-open-file-debug-myprojectlib-lib was necessary to get that far already). In case anyone figures that out, I would also be curious about an answer.
PS: thanks a lot Derik, really awesome tutorial to get started on the fundamentals! Your concise explanations already helped me heaps.
Good information on cmake for begginers like me helped me a lot ,Thank you 🙂
After reading a hundred other tutorials, there where more question-marks than answers in my head.
I almost lost hope for ever finding a decent explanation on how to write a cmakelists.txt…
… and then I found yours. *.*
Your tutorial helped a lot. Thanks!
Really informative
Awesome. Really good, clear explanations. Thanks very much.
Nice. Very Very Thanks !
Thanks a lot for this nice little tutorial!
Nice tutorial. I feel it is better than the official one.
Amazing explanation and exemplification… sincere thank you !!
I have looked at several cmake tutorials and was about to give up because none of them make sense. It is just beyond my comprehension. There are series of commands and it is not clear what exactly they are doing. Some would give very complicated use case with the equally complicated CMakeLists.txt! Your tutorial is the only one which made perfect sense to me! Thank you very much! In case you have other tutorials especially in embedded system, I would be very happy to know.
Thank you Derek!
So clear and precise example. Thank you so much for sharing the good work. 🙂
Thank you so much. This tutorial was perfect for my needs.
Really helpful for beginners like me! Thank you a lot!
Many Many thanks!
Helped me a lot! Many thanks!
Thanks, this was pitched at the perfect level for a newbie like me. 🙂
It was a really helpful article. Thanks a lot!
I’ve not found any tutorial clearer than this one for noobs as me, it helped me a lot, thank you very much!!
awesome tut on cmake! the best so far!
Dude, you are awesome.
This tutorial is quite heavily outdated and I would urge anyone not to use it as a reference anymore. For starters, no one should set 2.8.9 as the minimum required version anymore – that came out more than 6 years ago and CMake has moved on and evolved to become a much better build system.
Use 3.1 as the bare minimum, and read up on the target-based approach that should be used nowadays. Don’t use global state anymore everywhere.
Wow, you are awesome, thanks to you I learned a lot about cmake in a very short time!
It is one of the most beginner friendly tutorial for understanding CMake. Great job sir.
Thanks
Thanks – good first tutorial on Cmake.
Awesome tutorial. I wish others could explain things like you do 🙂
Excellent article, I’ve learnt a lot. Many thanks.
Thanks for the tutorial. Very useful for newbies.. 🙂
cannot find source file :/home/user/document/error in tried extension .c .C .c++ .cc .cpp .cxx .m .M cmakeList.txt.
.mm .h .hh .h++ .hm .hpp .hxx .in .txx
I am getting this error while building this project. https://github.com/apertus-open-source-cinema/opencine using Qt 5.8 . How can fix it
Thank you. It’s useful for me.
A wonderful succinct tutorial to the point.
Thanks for the sharing!
Thanks lot. It is very useful for me.
Extremely informative and helpful.
Thank you.
How to add different directories in CMakeLists.txt ?
I have source files in src, headers in include and few files from tests directory.
(The main function is calling functions which are defined in file from tests.)
Clear easy useful! thank you
The best source to get started with cmake. +1!
Thank you for a really wonderful article.
Thanks for the tutorial. It’s absurd how deep one has to dig on the internet to find a short proper introduction to cmake on the web
Thanks form Taiwan!!! really helpful
Thank you 🙂
Really thank you Sir. It is helpful for me.
Thanks, I learned a lot.
It’s really great! Thank you, Derek.
Thank you derek, it’s really useful to me.
Thank you ,it helps me use CMAKE on windows too.
Thanks a lot. Was very precise and yet to the point.
Simple and to the point tutorial. Thanks, Derek! Great work ; )
Thank you, very much. I was lost until I found your post. 🙂
You helped me a lot. Thank you very much! In my opinion, this is the best CMake tutorial for beginners.
Thank you very much for a simple CLEAR introduction to CMake
Thank you so much for a simple clear introduction to CMake
Hi Dr. Derek Molloy.
I used to no comment on the web. but you made me to do that.
just want to say THANK YOU.
Really nice tutorial for beginners. Really appreciate your effort.
I really wish you’d covered how to set a “–prefix” option. Compiling in the source tree is always a bad idea; for instance you want a debug version and an optimized version, which you put in different locations with the prefix.
Super helpful simple tutorial. Thanks!
this isl really helpful tutorial on cmake. thanks a lot for writing this up.
thanks a lot. They are very good cmake templates.
Compiling usestudentlib I get an error
Host Ubuntu 18.04
$ make
[ 50%] Linking CXX executable libtest
/usr/bin/ld: skipping incompatible /home/me/yocto-qemuarm-sumo/testcmake/exploringBB/extras/cmake/studentlib_shared/build/libtestStudent.so when searching for -ltestStudent
/usr/bin/ld: cannot find -ltestStudent
collect2: error: ld returned 1 exit status
CMakeFiles/libtest.dir/build.make:94: recipe for target ‘libtest’ failed
make[2]: *** [libtest] Error 1
CMakeFiles/Makefile2:67: recipe for target ‘CMakeFiles/libtest.dir/all’ failed
make[1]: *** [CMakeFiles/libtest.dir/all] Error 2
Makefile:83: recipe for target ‘all’ failed
make: *** [all] Error 2
… because I built my own shared library I had to change link_directories in usestudentlib’s CMakeLists.txt to point to it where you was using the prebult one wich is ARM. I am actually testing these exercises with x86
$ file libtestStudent.so
libtestStudent.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=2f4c2a3c62543821e3068e9ad14d4971d09690b6, not stripped
$ file build/libtestStudent.so
build/libtestStudent.so: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, BuildID[sha1]=edd51fbd5baeb2f8a21d08a204c85eaf46b5462c, not stripped
#For the shared library:
set ( PROJECT_LINK_LIBS libtestStudent.so )
link_directories( /home/me/yocto-qemuarm-sumo/testcmake/exploringBB/extras/cmake/studentlib_shared )
usestudentlib$ make
— Configuring done
— Generating done
— Build files have been written to: /home/me/yocto-qemuarm-sumo/testcmake/exploringBB/extras/cmake/usestudentlib
[ 50%] Linking CXX executable libtest
[100%] Built target libtest
Thank you Derek!
Thank you very much. This is useful with many examples.
Well explained and crystal clear about cmake..Nice!!!!
That was a brilliant and an on-point startup guide for CMake. Thanks Derek!
The static library built using the above way has no defintions of functions in it.
I tried to create a static library demo.a which inturn was linked to libconfig.a(for ubuntu).
When I did nm in this demo.a then the libconfig’s functions is marked as U in nm output.
How to get the definitions of other linked library in my built library.
Nice explanation for beginners . Thank you
Very good document. Very helpful!!
Thank you so much! This really helped me. It was beautifully explained
If you are an absolute beginner, and want to learn CMake, you can go through the lecture series ‘Master CMake for Cross-Platform C++ Project Building’ on ‘Udemy’ with 30 days money-back guarantee.
Drop the “return 0” from your examples. It’s not needed and adds to clutter.
Now I understand CMake better. The 5 different examples are enlightening. Many thanks
Thanks for not pretending that I am a retard, but instead getting straight to the point.
good tutorial.
Thank you for this post, sir!
Best intro to CMake, had me going in no time.
Best intro to CMake, had me going in no time.
Very nice tutorial! The examples are really helpful!
Many thanks to you.
Thank you, really helpful.
Thanx very much, really helpful