├── .gitignore ├── src ├── math.h ├── math.cc └── main.cc ├── LICENSE ├── test └── math_test.cc ├── CMakeLists.txt └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Build directory 2 | build/ 3 | 4 | # macOS 5 | .DS_Store 6 | 7 | # IDE 8 | /.idea/ 9 | /cmake-build-*/ 10 | -------------------------------------------------------------------------------- /src/math.h: -------------------------------------------------------------------------------- 1 | #ifndef CMAKE_TUTORIAL_MATH_H 2 | #define CMAKE_TUTORIAL_MATH_H 3 | 4 | namespace math { 5 | 6 | int add(int a, int b); 7 | int sub(int a, int b); 8 | int mul(int a, int b); 9 | 10 | } 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /src/math.cc: -------------------------------------------------------------------------------- 1 | namespace math { 2 | 3 | int add(int a, int b) { 4 | return a + b; 5 | } 6 | 7 | int sub(int a, int b) { 8 | return a - b; 9 | } 10 | 11 | int mul(int a, int b) { 12 | return a * b; 13 | } 14 | 15 | } 16 | 17 | -------------------------------------------------------------------------------- /src/main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "math.h" 3 | 4 | using namespace std; 5 | 6 | int main(int argc, char **argv) { 7 | int result; 8 | 9 | result = math::add(1, 2); 10 | cout << "add 1 + 2 : " << result << endl; 11 | 12 | result = math::add(4, 2); 13 | cout << "add 4 + 2 : " << result << endl; 14 | 15 | result = math::sub(1, 2); 16 | cout << "sub 1 - 2 : " << result << endl; 17 | 18 | result = math::sub(4, 2); 19 | cout << "sub 4 - 2 : " << result << endl; 20 | 21 | result = math::mul(1, 2); 22 | cout << "mul 1 * 2 : " << result << endl; 23 | 24 | result = math::mul(4, 2); 25 | cout << "mul 4 * 2 : " << result << endl; 26 | } 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Bayu Aldi Yansyah 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /test/math_test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../src/math.h" 3 | 4 | TEST(MathAddTest, PositiveNum) { 5 | EXPECT_EQ(2, math::add(1, 1)); 6 | EXPECT_EQ(10, math::add(2, 8)); 7 | EXPECT_EQ(100, math::add(50, 50)); 8 | } 9 | 10 | TEST(MathAddTest, ZeroB) { 11 | EXPECT_EQ(1, math::add(1, 0)); 12 | EXPECT_EQ(10, math::add(10, 0)); 13 | EXPECT_EQ(100, math::add(100, 0)); 14 | } 15 | 16 | TEST(MathSubTest, PositiveNum) { 17 | EXPECT_EQ(0, math::sub(1, 1)); 18 | EXPECT_EQ(-6, math::sub(2, 8)); 19 | EXPECT_EQ(100, math::sub(150, 50)); 20 | } 21 | 22 | TEST(MathSubTest, ZeroB) { 23 | EXPECT_EQ(1, math::sub(1, 0)); 24 | EXPECT_EQ(10, math::sub(10, 0)); 25 | EXPECT_EQ(100, math::sub(100, 0)); 26 | } 27 | 28 | TEST(MathMulTest, PositiveNum) { 29 | EXPECT_EQ(1, math::mul(1, 1)); 30 | EXPECT_EQ(16, math::mul(2, 8)); 31 | EXPECT_EQ(1500, math::mul(150, 10)); 32 | } 33 | 34 | TEST(MathMulTest, ZeroB) { 35 | EXPECT_EQ(0, math::mul(1, 0)); 36 | EXPECT_EQ(0, math::mul(10, 0)); 37 | EXPECT_EQ(0, math::mul(100, 0)); 38 | } 39 | 40 | int main(int argc, char **argv) { 41 | ::testing::InitGoogleTest(&argc, argv); 42 | return RUN_ALL_TESTS(); 43 | } 44 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.10) 2 | 3 | # Define the project 4 | project(cmake-tutorial) 5 | 6 | # GoogleTest requires at least C++11 7 | set(CMAKE_CXX_STANDARD 11) 8 | 9 | # Add definition for math library 10 | add_library(math src/math.cc) 11 | 12 | 13 | # Add definition for the cmake-tutorial binary 14 | add_executable(cmake-tutorial src/main.cc) 15 | target_link_libraries(cmake-tutorial math) 16 | 17 | 18 | # Third-party library 19 | include(ExternalProject) 20 | ExternalProject_Add(googletest 21 | PREFIX "${CMAKE_BINARY_DIR}/lib" 22 | GIT_REPOSITORY "https://github.com/google/googletest.git" 23 | GIT_TAG "main" 24 | CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/lib/installed 25 | ) 26 | 27 | 28 | # Prevent build on all targets build 29 | set_target_properties(googletest PROPERTIES EXCLUDE_FROM_ALL TRUE) 30 | 31 | 32 | # Define ${CMAKE_INSTALL_...} variables 33 | include(GNUInstallDirs) 34 | 35 | 36 | # Specify where third-party libraries are located 37 | link_directories(${CMAKE_BINARY_DIR}/lib/installed/${CMAKE_INSTALL_LIBDIR}) 38 | include_directories(${CMAKE_BINARY_DIR}/lib/installed/${CMAKE_INSTALL_INCLUDEDIR}) 39 | 40 | 41 | # This is required for googletest 42 | find_package(Threads REQUIRED) 43 | 44 | 45 | # Test 46 | add_executable(math_test test/math_test.cc) 47 | target_link_libraries(math_test math gtest Threads::Threads) 48 | 49 | 50 | # Make sure third-party is built before executable 51 | add_dependencies(math_test googletest) 52 | set_target_properties(math_test PROPERTIES EXCLUDE_FROM_ALL TRUE) 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CMake Tutorial 2 | 3 | This tutorial cover the following: 4 | 5 | 1. Build the project using simple `c++(1)` and `make(1)`. 6 | 2. Build the project using `cmake(1)`. 7 | 3. Build the project using `cmake(1)` with third party library. 8 | 9 | In this tutorial we will use the following project structure: 10 | 11 | ``` 12 | cmake-tutorial/ 13 | ├── CMakeLists.txt 14 | ├── README.md 15 | ├── src 16 | │   ├── main.cc 17 | │   ├── math.cc 18 | │   └── math.h 19 | └── test 20 | └── math_test.cc 21 | ``` 22 | 23 | Directory structure: 24 | 25 | - `src` : Directory for source code. 26 | - `test` : Directory for test. 27 | 28 | `src/main.cc` is our main executable and `src/math.{cc,h}` is an internal library that used by `src/main.cc`. 29 | 30 | We will start from the basic on how to build the project using `c++(1)` only 31 | and a simple `Makefile`. Then we define the build in `CMakeLists.txt` and 32 | using `cmake(1)` to generate complex `Makefile` for us. 33 | 34 | 35 | ## Install CMake 36 | 37 | First of all, you need to install `cmake`. 38 | 39 | On Ubuntu: 40 | 41 | ``` 42 | sudo apt-get install cmake 43 | ``` 44 | 45 | On macOS: 46 | 47 | ``` 48 | brew install cmake 49 | ``` 50 | 51 | Make sure the `cmake` is installed correctly: 52 | 53 | ``` 54 | % cmake --version 55 | cmake version 3.10.2 56 | 57 | CMake suite maintained and supported by Kitware (kitware.com/cmake). 58 | ``` 59 | 60 | ## Compiling & Linking 61 | 62 | We can build this project using the following command: 63 | 64 | ``` 65 | c++ src/main.cc src/math.cc -o cmake-tutorial 66 | ``` 67 | 68 | Or we can do the compile and linking on the separate steps 69 | 70 | ``` 71 | c++ -c src/math.cc -o math.o 72 | c++ src/main.cc math.o -o cmake-tutorial 73 | ``` 74 | 75 | ## Using Makefile 76 | 77 | We can automate the step to compile and link above using `Makefile`. 78 | First we need to create new `Makefile` in the root directory with the following content: 79 | 80 | ```makefile 81 | # Add definition to generate math.o object file 82 | math.o: src/math.cc src/math.h 83 | c++ -c src/math.cc -o math.o 84 | 85 | # Add definition to generate cmake-tutorial binary 86 | cmake-tutorial: math.o 87 | c++ src/main.cc math.o -o cmake-tutorial 88 | ``` 89 | 90 | Now we can run: 91 | 92 | ``` 93 | make cmake-tutorial 94 | ``` 95 | 96 | to build `cmake-tutorial` binary. If there are no changes in `src/{main,math}.cc` and `src/math.h`, 97 | the subsequent command will do nothing: 98 | 99 | ``` 100 | % make cmake-tutorial 101 | make: Nothing to be done for `cmake-tutorial'. 102 | ``` 103 | 104 | this is useful when working on larger project, we only compile the object that changes. 105 | 106 | ## Using CMake 107 | 108 | Now we know how to perform compiling and linking using the `C++` and `make` command. 109 | Now we can use `cmake` to do all of this for us. 110 | 111 | Create new `CMakeLists.txt` with the following content: 112 | 113 | ```cmake 114 | cmake_minimum_required (VERSION 3.10) 115 | 116 | # Define the project 117 | project(cmake-tutorial) 118 | 119 | # Add definition for math library 120 | add_library(math src/math.cc) 121 | 122 | # Add definition for the cmake-tutorial binary 123 | add_executable(cmake-tutorial src/main.cc) 124 | target_link_libraries(cmake-tutorial math) 125 | ``` 126 | 127 | We can generate the `Makefile` based on the definition above using the following command: 128 | 129 | ``` 130 | cmake . 131 | ``` 132 | 133 | Or create a `build` directory to store the generated files by CMake: 134 | 135 | ``` 136 | mkdir build 137 | cd build/ 138 | cmake .. 139 | ``` 140 | 141 | Now we can run `make cmake-tutorial` to build the binary. 142 | 143 | ``` 144 | % make cmake-tutorial 145 | Scanning dependencies of target math 146 | [ 25%] Building CXX object CMakeFiles/math.dir/src/math.cc.o 147 | [ 50%] Linking CXX static library libmath.a 148 | [ 50%] Built target math 149 | Scanning dependencies of target cmake-tutorial 150 | [ 75%] Building CXX object CMakeFiles/cmake-tutorial.dir/src/main.cc.o 151 | [100%] Linking CXX executable cmake-tutorial 152 | [100%] Built target cmake-tutorial 153 | ``` 154 | 155 | Or we can use the CMake directly via: 156 | 157 | ``` 158 | cmake --build . --target cmake-tutorial 159 | ``` 160 | 161 | ## Using CMake with 3rd-party library 162 | 163 | Suppose that we want to write a unit test for `math::add(a, b)`. 164 | We will use a [googletest](https://github.com/google/googletest) library to create and run the unit test. 165 | 166 | Add the following definition to `CMakeLists.txt`: 167 | 168 | ```cmake 169 | # Third-party library 170 | include(ExternalProject) 171 | ExternalProject_Add(googletest 172 | PREFIX "${CMAKE_BINARY_DIR}/lib" 173 | GIT_REPOSITORY "https://github.com/google/googletest.git" 174 | GIT_TAG "main" 175 | CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/lib/installed 176 | ) 177 | # Prevent build on all targets build 178 | set_target_properties(googletest PROPERTIES EXCLUDE_FROM_ALL TRUE) 179 | 180 | # Define ${CMAKE_INSTALL_...} variables 181 | include(GNUInstallDirs) 182 | 183 | # Specify where third-party libraries are located 184 | link_directories(${CMAKE_BINARY_DIR}/lib/installed/${CMAKE_INSTALL_LIBDIR}) 185 | include_directories(${CMAKE_BINARY_DIR}/lib/installed/${CMAKE_INSTALL_INCLUDEDIR}) 186 | 187 | # This is required for googletest 188 | find_package(Threads REQUIRED) 189 | 190 | # Test 191 | add_executable(math_test test/math_test.cc) 192 | target_link_libraries(math_test math gtest Threads::Threads) 193 | # Make sure third-party is built before executable 194 | add_dependencies(math_test googletest) 195 | set_target_properties(math_test PROPERTIES EXCLUDE_FROM_ALL TRUE) 196 | ``` 197 | 198 | Re-generate the build files using the following command: 199 | 200 | ``` 201 | cd build/ 202 | cmake .. 203 | ``` 204 | 205 | Build the unit test: 206 | 207 | ``` 208 | cmake --build . --target math_test 209 | ``` 210 | 211 | Run the test: 212 | 213 | ``` 214 | % ./math_test 215 | [==========] Running 6 tests from 3 test cases. 216 | [----------] Global test environment set-up. 217 | [----------] 2 tests from MathAddTest 218 | [ RUN ] MathAddTest.PositiveNum 219 | [ OK ] MathAddTest.PositiveNum (0 ms) 220 | [ RUN ] MathAddTest.ZeroB 221 | [ OK ] MathAddTest.ZeroB (0 ms) 222 | [----------] 2 tests from MathAddTest (0 ms total) 223 | 224 | [----------] 2 tests from MathSubTest 225 | [ RUN ] MathSubTest.PositiveNum 226 | [ OK ] MathSubTest.PositiveNum (0 ms) 227 | [ RUN ] MathSubTest.ZeroB 228 | [ OK ] MathSubTest.ZeroB (0 ms) 229 | [----------] 2 tests from MathSubTest (0 ms total) 230 | 231 | [----------] 2 tests from MathMulTest 232 | [ RUN ] MathMulTest.PositiveNum 233 | [ OK ] MathMulTest.PositiveNum (0 ms) 234 | [ RUN ] MathMulTest.ZeroB 235 | [ OK ] MathMulTest.ZeroB (0 ms) 236 | [----------] 2 tests from MathMulTest (0 ms total) 237 | 238 | [----------] Global test environment tear-down 239 | [==========] 6 tests from 3 test cases ran. (0 ms total) 240 | [ PASSED ] 6 tests. 241 | ``` 242 | 243 | Done. 244 | 245 | 246 | ### IDE Support 247 | 248 | If you are using `CLion`, the google test will automatically detected. 249 | 250 | ![CLion](https://s9.postimg.org/ugqkdw6nh/Screen_Shot_2018-02-16_at_21.03.10.png) 251 | 252 | Visual studio also support cmake 253 | --------------------------------------------------------------------------------