├── .gitignore ├── .travis.yml ├── 01-basic ├── A-hello-cmake │ ├── CMakeLists.txt │ ├── README.adoc │ └── main.cpp ├── B-hello-headers │ ├── CMakeLists.txt │ ├── README.adoc │ ├── include │ │ └── Hello.h │ └── src │ │ ├── Hello.cpp │ │ └── main.cpp ├── C-static-library │ ├── CMakeLists.txt │ ├── README.adoc │ ├── include │ │ └── static │ │ │ └── Hello.h │ └── src │ │ ├── Hello.cpp │ │ └── main.cpp ├── D-shared-library │ ├── CMakeLists.txt │ ├── README.adoc │ ├── include │ │ └── shared │ │ │ └── Hello.h │ └── src │ │ ├── Hello.cpp │ │ └── main.cpp ├── E-installing │ ├── CMakeLists.txt │ ├── README.adoc │ ├── cmake-examples.conf │ ├── include │ │ └── installing │ │ │ └── Hello.h │ └── src │ │ ├── Hello.cpp │ │ └── main.cpp ├── F-build-type │ ├── CMakeLists.txt │ ├── README.adoc │ ├── cmake-gui-build-type.png │ └── main.cpp ├── G-compile-flags │ ├── CMakeLists.txt │ ├── README.adoc │ └── main.cpp ├── H-third-party-library │ ├── CMakeLists.txt │ ├── README.adoc │ └── main.cpp ├── I-compiling-with-clang │ ├── CMakeLists.txt │ ├── README.adoc │ ├── main.cpp │ ├── pre_test.sh │ └── run_test.sh ├── J-building-with-ninja │ ├── CMakeLists.txt │ ├── README.adoc │ ├── main.cpp │ ├── pre_test.sh │ └── run_test.sh ├── K-imported-targets │ ├── CMakeLists.txt │ ├── README.adoc │ ├── main.cpp │ └── run_test.sh ├── L-cpp-standard │ ├── README.adoc │ ├── i-common-method │ │ ├── CMakeLists.txt │ │ ├── README.adoc │ │ └── main.cpp │ ├── ii-cxx-standard │ │ ├── CMakeLists.txt │ │ ├── README.adoc │ │ └── main.cpp │ └── iii-compile-features │ │ ├── CMakeLists.txt │ │ ├── README.adoc │ │ └── main.cpp └── README.adoc ├── 02-sub-projects ├── A-basic │ ├── CMakeLists.txt │ ├── README.adoc │ ├── subbinary │ │ ├── CMakeLists.txt │ │ └── main.cpp │ ├── sublibrary1 │ │ ├── CMakeLists.txt │ │ ├── include │ │ │ └── sublib1 │ │ │ │ └── sublib1.h │ │ └── src │ │ │ └── sublib1.cpp │ └── sublibrary2 │ │ ├── CMakeLists.txt │ │ └── include │ │ └── sublib2 │ │ └── sublib2.h └── README.adoc ├── 03-code-generation ├── README.adoc ├── configure-files │ ├── CMakeLists.txt │ ├── README.adoc │ ├── main.cpp │ ├── path.h.in │ └── ver.h.in └── protobuf │ ├── AddressBook.proto │ ├── CMakeLists.txt │ ├── README.adoc │ └── main.cpp ├── 04-static-analysis ├── README.adoc ├── clang-analyzer │ ├── CMakeLists.txt │ ├── README.adoc │ ├── run_test.sh │ ├── subproject1 │ │ ├── CMakeLists.txt │ │ └── main1.cpp │ └── subproject2 │ │ ├── CMakeLists.txt │ │ └── main2.cpp ├── clang-format │ ├── .clang-format │ ├── CMakeLists.txt │ ├── README.adoc │ ├── cmake │ │ ├── modules │ │ │ ├── FindClangFormat.cmake │ │ │ └── clang-format.cmake │ │ └── scripts │ │ │ ├── clang-format-check-changed │ │ │ └── clang-format-check-changed.py │ ├── run_test.sh │ ├── subproject1 │ │ ├── CMakeLists.txt │ │ └── main1.cpp │ └── subproject2 │ │ ├── CMakeLists.txt │ │ └── main2.cpp ├── cppcheck-compile-commands │ ├── .cppcheck_suppressions │ ├── CMakeLists.txt │ ├── README.adoc │ ├── cmake │ │ └── modules │ │ │ └── FindCppCheck.cmake │ ├── run_test.sh │ ├── subproject1 │ │ ├── CMakeLists.txt │ │ └── main1.cpp │ └── subproject2 │ │ ├── CMakeLists.txt │ │ └── main2.cpp └── cppcheck │ ├── CMakeLists.txt │ ├── README.adoc │ ├── cmake │ ├── analysis.cmake │ └── modules │ │ └── FindCppCheck.cmake │ ├── run_test.sh │ ├── subproject1 │ ├── CMakeLists.txt │ └── main1.cpp │ └── subproject2 │ ├── CMakeLists.txt │ └── main2.cpp ├── 05-unit-testing ├── README.adoc ├── boost │ ├── CMakeLists.txt │ ├── Palindrome.cpp │ ├── Palindrome.h │ ├── README.adoc │ ├── Reverse.cpp │ ├── Reverse.h │ ├── main.cpp │ ├── post_test.sh │ └── unit_tests.cpp ├── catch2-vendored │ ├── 3rd_party │ │ └── catch2 │ │ │ ├── CMakeLists.txt │ │ │ └── catch2 │ │ │ └── catch.hpp │ ├── CMakeLists.txt │ ├── Palindrome.cpp │ ├── Palindrome.h │ ├── README.adoc │ ├── Reverse.cpp │ ├── Reverse.h │ ├── main.cpp │ ├── post_test.sh │ └── unit_tests.cpp └── google-test-download │ ├── 3rd_party │ └── google-test │ │ ├── CMakeLists.txt │ │ └── CMakeLists.txt.in │ ├── CMakeLists.txt │ ├── Palindrome.cpp │ ├── Palindrome.h │ ├── README.adoc │ ├── Reverse.cpp │ ├── Reverse.h │ ├── main.cpp │ ├── post_test.sh │ ├── run_test.sh │ └── unit_tests.cpp ├── 06-installer ├── README.adoc └── deb │ ├── CMakeLists.txt │ ├── README.adoc │ ├── cmake-examples.conf │ ├── include │ └── Hello.h │ ├── post_test.sh │ └── src │ ├── Hello.cpp │ └── main.cpp ├── 07-package-management ├── A-using-system-provide-packages │ └── README.adoc ├── B-vendoring-code │ └── README.adoc ├── C-external-project-add │ └── README.adoc ├── D-conan │ ├── README.adoc │ ├── i-basic │ │ ├── CMakeLists.txt │ │ ├── README.adoc │ │ ├── conanfile.txt │ │ ├── main.cpp │ │ └── run_test.sh │ └── ii-basic-targets │ │ ├── CMakeLists.txt │ │ ├── README.adoc │ │ ├── conanfile.txt │ │ ├── main.cpp │ │ └── run_test.sh └── README.adoc ├── LICENSE ├── README.adoc ├── cmake-examples.sublime-project ├── dockerfiles ├── README.adoc ├── setup.sh ├── ubuntu14.04-cmake-3.4.3 ├── ubuntu14.04-default-2.8.12.2 ├── ubuntu16.04-cmake-3.10.3 └── ubuntu16.04-default-cmake-3.5.1 └── test.sh /.gitignore: -------------------------------------------------------------------------------- 1 | CMakeCache.txt 2 | CMakeFiles 3 | Makefile 4 | cmake_install.cmake 5 | install_manifest.txt 6 | 7 | # 8 | # Sublime Test 9 | # 10 | # cache files for sublime text 11 | *.tmlanguage.cache 12 | *.tmPreferences.cache 13 | *.stTheme.cache 14 | 15 | # workspace files are user-specific 16 | *.sublime-workspace 17 | 18 | # project files should be checked into the repository, unless a significant 19 | # proportion of contributors will probably not be using SublimeText 20 | # *.sublime-project 21 | 22 | # 23 | # C / C++ 24 | # 25 | 26 | # Compiled Object files 27 | *.slo 28 | *.lo 29 | *.o 30 | *.obj 31 | *.ko 32 | *.elf 33 | 34 | # Precompiled Headers 35 | *.gch 36 | *.pch 37 | 38 | # Compiled Dynamic libraries 39 | *.so 40 | *.dylib 41 | *.dll 42 | *.so.* 43 | *.dylib 44 | 45 | # Fortran module files 46 | *.mod 47 | 48 | # Compiled Static libraries 49 | *.lai 50 | *.la 51 | *.a 52 | *.lib 53 | *.lo 54 | 55 | # Executables 56 | *.exe 57 | *.out 58 | *.app 59 | 60 | /**/build 61 | /**/build.* 62 | 63 | .tags 64 | .vscode 65 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | services: 3 | - docker 4 | sudo: required 5 | compiler: 6 | - gcc 7 | before_install: 8 | - docker pull matrim/cmake-examples:3.5.1 9 | - docker pull matrim/cmake-examples:3.10.3 10 | script: 11 | - docker run --rm -v $PWD:/data/code -e DEV_UID=`id -u` -e DEV_GID=`id -g` -it matrim/cmake-examples:3.5.1 /data/code/test.sh 12 | - docker run --rm -v $PWD:/data/code -e DEV_UID=`id -u` -e DEV_GID=`id -g` -it matrim/cmake-examples:3.10.3 /data/code/test.sh 13 | branches: 14 | except: 15 | - gh-pages 16 | notifications: 17 | email: true 18 | os: 19 | - linux 20 | -------------------------------------------------------------------------------- /01-basic/A-hello-cmake/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Set the minimum version of CMake that can be used 2 | # To find the cmake version run 3 | # $ cmake --version 4 | cmake_minimum_required(VERSION 3.5) 5 | 6 | # Set the project name 7 | project (hello_cmake) 8 | 9 | # Add an executable 10 | add_executable(hello_cmake main.cpp) 11 | -------------------------------------------------------------------------------- /01-basic/A-hello-cmake/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | std::cout << "Hello CMake!" << std::endl; 6 | return 0; 7 | } -------------------------------------------------------------------------------- /01-basic/B-hello-headers/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Set the minimum version of CMake that can be used 2 | # To find the cmake version run 3 | # $ cmake --version 4 | cmake_minimum_required(VERSION 3.5) 5 | 6 | # Set the project name 7 | project (hello_headers) 8 | 9 | # Create a sources variable with a link to all cpp files to compile 10 | set(SOURCES 11 | src/Hello.cpp 12 | src/main.cpp 13 | ) 14 | 15 | # Add an executable with the above sources 16 | add_executable(hello_headers ${SOURCES}) 17 | 18 | # Set the directories that should be included in the build command for this target 19 | # when running g++ these will be included as -I/directory/path/ 20 | target_include_directories(hello_headers 21 | PRIVATE 22 | ${PROJECT_SOURCE_DIR}/include 23 | ) 24 | -------------------------------------------------------------------------------- /01-basic/B-hello-headers/include/Hello.h: -------------------------------------------------------------------------------- 1 | #ifndef __HELLO_H__ 2 | #define __HELLO_H__ 3 | 4 | class Hello 5 | { 6 | public: 7 | void print(); 8 | }; 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /01-basic/B-hello-headers/src/Hello.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "Hello.h" 4 | 5 | void Hello::print() 6 | { 7 | std::cout << "Hello Headers!" << std::endl; 8 | } 9 | -------------------------------------------------------------------------------- /01-basic/B-hello-headers/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "Hello.h" 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | Hello hi; 6 | hi.print(); 7 | return 0; 8 | } -------------------------------------------------------------------------------- /01-basic/C-static-library/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(hello_library) 4 | 5 | ############################################################ 6 | # Create a library 7 | ############################################################ 8 | 9 | #Generate the static library from the library sources 10 | add_library(hello_library STATIC 11 | src/Hello.cpp 12 | ) 13 | 14 | target_include_directories(hello_library 15 | PUBLIC 16 | ${PROJECT_SOURCE_DIR}/include 17 | ) 18 | 19 | 20 | ############################################################ 21 | # Create an executable 22 | ############################################################ 23 | 24 | # Add an executable with the above sources 25 | add_executable(hello_binary 26 | src/main.cpp 27 | ) 28 | 29 | # link the new hello_library target with the hello_binary target 30 | target_link_libraries( hello_binary 31 | PRIVATE 32 | hello_library 33 | ) 34 | -------------------------------------------------------------------------------- /01-basic/C-static-library/README.adoc: -------------------------------------------------------------------------------- 1 | = Static Library 2 | :toc: 3 | :toc-placement!: 4 | 5 | toc::[] 6 | 7 | # Introduction 8 | 9 | Shows a hello world example which first creates and links a static library. This is a 10 | simplified example showing the library and binary in the same folder. Typically 11 | these would be in sub-projects as described in section link:../../02-sub-projects[02-sub-projects] 12 | 13 | The files in this tutorial are below: 14 | 15 | ``` 16 | $ tree 17 | . 18 | ├── CMakeLists.txt 19 | ├── include 20 | │   └── static 21 | │   └── Hello.h 22 | └── src 23 | ├── Hello.cpp 24 | └── main.cpp 25 | ``` 26 | 27 | * link:CMakeLists.txt[] - Contains the CMake commands you wish to run 28 | * link:include/static/Hello.h[] - The header file to include 29 | * link:src/Hello.cpp[] - A source file to compile 30 | * link:src/main.cpp[] - The source file with main 31 | 32 | 33 | # Concepts 34 | 35 | ## Adding a Static Library 36 | 37 | The +add_library()+ function is used to create a library from some source files. 38 | This is called as follows: 39 | 40 | [source,cmake] 41 | ---- 42 | add_library(hello_library STATIC 43 | src/Hello.cpp 44 | ) 45 | ---- 46 | 47 | This will be used to create a static library with the name libhello_library.a with 48 | the sources in the +add_library+ call. 49 | 50 | [NOTE] 51 | ==== 52 | As mentioned in the previous example, we pass the source files directly to the 53 | +add_library+ call, as recommended for modern CMake. 54 | ==== 55 | 56 | ## Populating Including Directories 57 | 58 | In this example, we include directories in the library using the +target_include_directories()+ function with the scope set to +PUBLIC+. 59 | 60 | [source,cmake] 61 | ---- 62 | target_include_directories(hello_library 63 | PUBLIC 64 | ${PROJECT_SOURCE_DIR}/include 65 | ) 66 | ---- 67 | 68 | This will cause the included directory used in the following places: 69 | 70 | * When compiling the library 71 | * When compiling any additional target that links the library. 72 | 73 | The meaning of scopes are: 74 | 75 | * +PRIVATE+ - the directory is added to this target's include directories 76 | * +INTERFACE+ - the directory is added to the include directories for any targets that link this library. 77 | * +PUBLIC+ - As above, it is included in this library and also any targets that link this library. 78 | 79 | 80 | [TIP] 81 | ==== 82 | For public headers it is often a good idea to have your include folder be "namespaced" 83 | with sub-directories. 84 | 85 | The directory passed to +target_include_directories+ will be the root of your 86 | include directory tree and your C++ files should include the path from there to your header. 87 | 88 | For this example you can see that we do it as follows: 89 | [source,cpp] 90 | ---- 91 | #include "static/Hello.h" 92 | ---- 93 | 94 | Using this method means that there is less chance of header filename clashes when 95 | you use multiple libraries in your project. 96 | ==== 97 | 98 | ## Linking a Library 99 | 100 | When creating an executable that will use your library you must tell the compiler 101 | about the library. This can be done using the +target_link_libraries()+ function. 102 | 103 | [source,cmake] 104 | ---- 105 | add_executable(hello_binary 106 | src/main.cpp 107 | ) 108 | 109 | target_link_libraries( hello_binary 110 | PRIVATE 111 | hello_library 112 | ) 113 | ---- 114 | 115 | This tells CMake to link the hello_library against the hello_binary executable 116 | during link time. It will also propagate any include directories with +PUBLIC+ or +INTERFACE+ scope 117 | from the linked library target. 118 | 119 | An example of this being called by the compiler is 120 | 121 | ``` 122 | /usr/bin/c++ CMakeFiles/hello_binary.dir/src/main.cpp.o -o hello_binary -rdynamic libhello_library.a 123 | ``` 124 | 125 | 126 | # Building the Example 127 | 128 | [source,bash] 129 | ---- 130 | $ mkdir build 131 | 132 | $ cd build 133 | 134 | $ cmake .. 135 | -- The C compiler identification is GNU 4.8.4 136 | -- The CXX compiler identification is GNU 4.8.4 137 | -- Check for working C compiler: /usr/bin/cc 138 | -- Check for working C compiler: /usr/bin/cc -- works 139 | -- Detecting C compiler ABI info 140 | -- Detecting C compiler ABI info - done 141 | -- Check for working CXX compiler: /usr/bin/c++ 142 | -- Check for working CXX compiler: /usr/bin/c++ -- works 143 | -- Detecting CXX compiler ABI info 144 | -- Detecting CXX compiler ABI info - done 145 | -- Configuring done 146 | -- Generating done 147 | -- Build files have been written to: /home/matrim/workspace/cmake-examples/01-basic/C-static-library/build 148 | 149 | $ make 150 | Scanning dependencies of target hello_library 151 | [ 50%] Building CXX object CMakeFiles/hello_library.dir/src/Hello.cpp.o 152 | Linking CXX static library libhello_library.a 153 | [ 50%] Built target hello_library 154 | Scanning dependencies of target hello_binary 155 | [100%] Building CXX object CMakeFiles/hello_binary.dir/src/main.cpp.o 156 | Linking CXX executable hello_binary 157 | [100%] Built target hello_binary 158 | 159 | $ ls 160 | CMakeCache.txt CMakeFiles cmake_install.cmake hello_binary libhello_library.a Makefile 161 | 162 | $ ./hello_binary 163 | Hello Static Library! 164 | ---- 165 | -------------------------------------------------------------------------------- /01-basic/C-static-library/include/static/Hello.h: -------------------------------------------------------------------------------- 1 | #ifndef __HELLO_H__ 2 | #define __HELLO_H__ 3 | 4 | class Hello 5 | { 6 | public: 7 | void print(); 8 | }; 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /01-basic/C-static-library/src/Hello.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "static/Hello.h" 4 | 5 | void Hello::print() 6 | { 7 | std::cout << "Hello Static Library!" << std::endl; 8 | } 9 | -------------------------------------------------------------------------------- /01-basic/C-static-library/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "static/Hello.h" 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | Hello hi; 6 | hi.print(); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /01-basic/D-shared-library/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(hello_library) 4 | 5 | ############################################################ 6 | # Create a library 7 | ############################################################ 8 | 9 | #Generate the shared library from the library sources 10 | add_library(hello_library SHARED 11 | src/Hello.cpp 12 | ) 13 | add_library(hello::library ALIAS hello_library) 14 | 15 | target_include_directories(hello_library 16 | PUBLIC 17 | ${PROJECT_SOURCE_DIR}/include 18 | ) 19 | 20 | ############################################################ 21 | # Create an executable 22 | ############################################################ 23 | 24 | # Add an executable with the above sources 25 | add_executable(hello_binary 26 | src/main.cpp 27 | ) 28 | 29 | # link the new hello_library target with the hello_binary target 30 | target_link_libraries( hello_binary 31 | PRIVATE 32 | hello::library 33 | ) 34 | -------------------------------------------------------------------------------- /01-basic/D-shared-library/README.adoc: -------------------------------------------------------------------------------- 1 | = Shared Library 2 | :toc: 3 | :toc-placement!: 4 | 5 | toc::[] 6 | 7 | # Introduction 8 | 9 | Shows a hello world example which first creates and links a shared library. 10 | 11 | This also shows how to create an link:https://cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html#alias-targets[alias target] 12 | 13 | The files in this tutorial are below: 14 | 15 | ``` 16 | $ tree 17 | . 18 | ├── CMakeLists.txt 19 | ├── include 20 | │   └── shared 21 | │   └── Hello.h 22 | └── src 23 | ├── Hello.cpp 24 | └── main.cpp 25 | ``` 26 | 27 | * link:CMakeLists.txt[] - Contains the CMake commands you wish to run 28 | * link:include/shared/Hello.h[] - The header file to include 29 | * link:src/Hello.cpp[] - A source file to compile 30 | * link:src/main.cpp[] - The source file with main 31 | 32 | 33 | # Concepts 34 | 35 | ## Adding a Shared Library 36 | 37 | As with the previous example on static libraries, the +add_library()+ function 38 | is also used to create a shared library from some source files. 39 | This is called as follows: 40 | 41 | [source,cmake] 42 | ---- 43 | add_library(hello_library SHARED 44 | src/Hello.cpp 45 | ) 46 | ---- 47 | 48 | This will be used to create a shared library with the name libhello_library.so with 49 | the sources passed to the +add_library()+ function. 50 | 51 | ## Alias Target 52 | 53 | As the name suggests an link:https://cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html#alias-targets[alias target] is an alternative name for a target that can be used instead of the real target name in read-only contexts. 54 | 55 | [source,cmake] 56 | ---- 57 | add_library(hello::library ALIAS hello_library) 58 | ---- 59 | 60 | As shown below, this allows you to reference the target using the alias name when linking it against other targets. 61 | 62 | ## Linking a Shared Library 63 | 64 | Linking a shared library is the same as linking a static library. When creating your 65 | executable use the the +target_link_library()+ function to point to your library 66 | 67 | [source,cmake] 68 | ---- 69 | add_executable(hello_binary 70 | src/main.cpp 71 | ) 72 | 73 | target_link_libraries(hello_binary 74 | PRIVATE 75 | hello::library 76 | ) 77 | ---- 78 | 79 | This tells CMake to link the hello_library against the hello_binary executable using the alias target name. 80 | 81 | An example of this being called by the linker is 82 | 83 | ``` 84 | /usr/bin/c++ CMakeFiles/hello_binary.dir/src/main.cpp.o -o hello_binary -rdynamic libhello_library.so -Wl,-rpath,/home/matrim/workspace/cmake-examples/01-basic/D-shared-library/build 85 | ``` 86 | 87 | # Building the Example 88 | 89 | [source,bash] 90 | ---- 91 | $ mkdir build 92 | 93 | $ cd build 94 | 95 | $ cmake .. 96 | -- The C compiler identification is GNU 4.8.4 97 | -- The CXX compiler identification is GNU 4.8.4 98 | -- Check for working C compiler: /usr/bin/cc 99 | -- Check for working C compiler: /usr/bin/cc -- works 100 | -- Detecting C compiler ABI info 101 | -- Detecting C compiler ABI info - done 102 | -- Check for working CXX compiler: /usr/bin/c++ 103 | -- Check for working CXX compiler: /usr/bin/c++ -- works 104 | -- Detecting CXX compiler ABI info 105 | -- Detecting CXX compiler ABI info - done 106 | -- Configuring done 107 | -- Generating done 108 | -- Build files have been written to: /home/matrim/workspace/cmake-examples/01-basic/D-shared-library/build 109 | 110 | $ make 111 | Scanning dependencies of target hello_library 112 | [ 50%] Building CXX object CMakeFiles/hello_library.dir/src/Hello.cpp.o 113 | Linking CXX shared library libhello_library.so 114 | [ 50%] Built target hello_library 115 | Scanning dependencies of target hello_binary 116 | [100%] Building CXX object CMakeFiles/hello_binary.dir/src/main.cpp.o 117 | Linking CXX executable hello_binary 118 | [100%] Built target hello_binary 119 | 120 | $ ls 121 | CMakeCache.txt CMakeFiles cmake_install.cmake hello_binary libhello_library.so Makefile 122 | 123 | $ ./hello_binary 124 | Hello Shared Library! 125 | ---- 126 | -------------------------------------------------------------------------------- /01-basic/D-shared-library/include/shared/Hello.h: -------------------------------------------------------------------------------- 1 | #ifndef __HELLO_H__ 2 | #define __HELLO_H__ 3 | 4 | class Hello 5 | { 6 | public: 7 | void print(); 8 | }; 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /01-basic/D-shared-library/src/Hello.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "shared/Hello.h" 4 | 5 | void Hello::print() 6 | { 7 | std::cout << "Hello Shared Library!" << std::endl; 8 | } 9 | -------------------------------------------------------------------------------- /01-basic/D-shared-library/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "shared/Hello.h" 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | Hello hi; 6 | hi.print(); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /01-basic/E-installing/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(cmake_examples_install) 4 | 5 | ############################################################ 6 | # Create a library 7 | ############################################################ 8 | 9 | #Generate the shared library from the library sources 10 | add_library(cmake_examples_inst SHARED 11 | src/Hello.cpp 12 | ) 13 | 14 | target_include_directories(cmake_examples_inst 15 | PUBLIC 16 | ${PROJECT_SOURCE_DIR}/include 17 | ) 18 | 19 | ############################################################ 20 | # Create an executable 21 | ############################################################ 22 | 23 | # Add an executable with the above sources 24 | add_executable(cmake_examples_inst_bin 25 | src/main.cpp 26 | ) 27 | 28 | # link the new hello_library target with the hello_binary target 29 | target_link_libraries( cmake_examples_inst_bin 30 | PRIVATE 31 | cmake_examples_inst 32 | ) 33 | 34 | ############################################################ 35 | # Install 36 | ############################################################ 37 | 38 | # Binaries 39 | install (TARGETS cmake_examples_inst_bin 40 | DESTINATION bin) 41 | 42 | # Library 43 | # Note: may not work on windows 44 | install (TARGETS cmake_examples_inst 45 | LIBRARY DESTINATION lib) 46 | 47 | # Header files 48 | install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/ 49 | DESTINATION include) 50 | 51 | # Config 52 | install (FILES cmake-examples.conf 53 | DESTINATION etc) 54 | -------------------------------------------------------------------------------- /01-basic/E-installing/README.adoc: -------------------------------------------------------------------------------- 1 | = Installing 2 | :toc: 3 | :toc-placement!: 4 | 5 | toc::[] 6 | 7 | # Introduction 8 | 9 | This example shows how to generate a `make install` target to install files and 10 | binaries on your system. This is based on the previous shared library example. 11 | 12 | The files in this tutorial are below: 13 | 14 | ``` 15 | $ tree 16 | . 17 | ├── cmake-examples.conf 18 | ├── CMakeLists.txt 19 | ├── include 20 | │   └── installing 21 | │   └── Hello.h 22 | ├── README.adoc 23 | └── src 24 | ├── Hello.cpp 25 | └── main.cpp 26 | ``` 27 | 28 | * link:CMakeLists.txt[] - Contains the CMake commands you wish to run 29 | * link:cmake-examples.conf[] - An example configuration file 30 | * link:include/installing/Hello.h[] - The header file to include 31 | * link:src/Hello.cpp[] - A source file to compile 32 | * link:src/main.cpp[] - The source file with main 33 | 34 | # Concepts 35 | 36 | ## Installing 37 | 38 | CMake offers the ability to add a `make install` target to allow a user to 39 | install binaries, libraries and other files. The base install location is controlled 40 | by the variable +CMAKE_INSTALL_PREFIX+ which can be set using ccmake or by calling 41 | cmake with `cmake .. -DCMAKE_INSTALL_PREFIX=/install/location` 42 | 43 | The files that are installed are controlled by the https://cmake.org/cmake/help/v3.0/command/install.html[+install()+] function. 44 | 45 | [source,cmake] 46 | ---- 47 | install (TARGETS cmake_examples_inst_bin 48 | DESTINATION bin) 49 | ---- 50 | 51 | Install the binary generated from the target cmake_examples_inst_bin target to 52 | the destination +${CMAKE_INSTALL_PREFIX}/bin+ 53 | 54 | [source,cmake] 55 | ---- 56 | install (TARGETS cmake_examples_inst 57 | LIBRARY DESTINATION lib) 58 | ---- 59 | 60 | Install the shared library generated from the target cmake_examples_inst target to 61 | the destination +${CMAKE_INSTALL_PREFIX}/lib+ 62 | 63 | [NOTE] 64 | ==== 65 | This may not work on windows. On platforms that have DLL targets you 66 | may need to add the following 67 | 68 | [source,cmake] 69 | ---- 70 | install (TARGETS cmake_examples_inst 71 | LIBRARY DESTINATION lib 72 | RUNTIME DESTINATION bin) 73 | ---- 74 | ==== 75 | 76 | 77 | [source,cmake] 78 | ---- 79 | install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/ 80 | DESTINATION include) 81 | ---- 82 | 83 | Install the header files for developing against the +cmake_examples_inst+ library 84 | into the +${CMAKE_INSTALL_PREFIX}/include+ directory. 85 | 86 | [source,cmake] 87 | ---- 88 | install (FILES cmake-examples.conf 89 | DESTINATION etc) 90 | ---- 91 | 92 | Install a configuration file to the destination +${CMAKE_INSTALL_PREFIX}/etc+ 93 | 94 | After `make install` has been run, CMake generates an install_manifest.txt file 95 | which includes details on all installed files. 96 | 97 | [NOTE] 98 | ==== 99 | If you run the `make install` command as root, the install_manifest.txt file will 100 | be owned by root. 101 | ==== 102 | 103 | # Building the Example 104 | 105 | [source,bash] 106 | ---- 107 | $ mkdir build 108 | 109 | $ cd build/ 110 | 111 | $ cmake .. 112 | -- The C compiler identification is GNU 4.8.4 113 | -- The CXX compiler identification is GNU 4.8.4 114 | -- Check for working C compiler: /usr/bin/cc 115 | -- Check for working C compiler: /usr/bin/cc -- works 116 | -- Detecting C compiler ABI info 117 | -- Detecting C compiler ABI info - done 118 | -- Check for working CXX compiler: /usr/bin/c++ 119 | -- Check for working CXX compiler: /usr/bin/c++ -- works 120 | -- Detecting CXX compiler ABI info 121 | -- Detecting CXX compiler ABI info - done 122 | -- Configuring done 123 | -- Generating done 124 | -- Build files have been written to: /home/matrim/workspace/cmake-examples/01-basic/E-installing/build 125 | 126 | $ make 127 | Scanning dependencies of target cmake_examples_inst 128 | [ 50%] Building CXX object CMakeFiles/cmake_examples_inst.dir/src/Hello.cpp.o 129 | Linking CXX shared library libcmake_examples_inst.so 130 | [ 50%] Built target cmake_examples_inst 131 | Scanning dependencies of target cmake_examples_inst_bin 132 | [100%] Building CXX object CMakeFiles/cmake_examples_inst_bin.dir/src/main.cpp.o 133 | Linking CXX executable cmake_examples_inst_bin 134 | [100%] Built target cmake_examples_inst_bin 135 | 136 | $ sudo make install 137 | [sudo] password for matrim: 138 | [ 50%] Built target cmake_examples_inst 139 | [100%] Built target cmake_examples_inst_bin 140 | Install the project... 141 | -- Install configuration: "" 142 | -- Installing: /usr/local/bin/cmake_examples_inst_bin 143 | -- Removed runtime path from "/usr/local/bin/cmake_examples_inst_bin" 144 | -- Installing: /usr/local/lib/libcmake_examples_inst.so 145 | -- Installing: /usr/local/etc/cmake-examples.conf 146 | 147 | $ cat install_manifest.txt 148 | /usr/local/bin/cmake_examples_inst_bin 149 | /usr/local/lib/libcmake_examples_inst.so 150 | /usr/local/etc/cmake-examples.conf 151 | 152 | $ ls /usr/local/bin/ 153 | cmake_examples_inst_bin 154 | 155 | $ ls /usr/local/lib 156 | libcmake_examples_inst.so 157 | 158 | $ ls /usr/local/etc/ 159 | cmake-examples.conf 160 | 161 | $ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib cmake_examples_inst_bin 162 | Hello Install! 163 | ---- 164 | 165 | [NOTE] 166 | ==== 167 | If `/usr/local/lib` is not in your library path you may need to add it to the 168 | path before running the binary. 169 | ==== 170 | 171 | [[extra-notes]] 172 | Extra Notes 173 | ~~~~~~~~~~~ 174 | 175 | [[default-location]] 176 | Overriding the default install location 177 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 178 | 179 | As mentioned the default install location is set from the +CMAKE_INSTALL_PREFIX+, 180 | which defaults to `/usr/local/` 181 | 182 | If you want to change this default location for all users you can add the 183 | following code to your top level CMakeLists.txt before adding any binaries or 184 | libraries. 185 | 186 | [source,cmake] 187 | ---- 188 | if( CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT ) 189 | message(STATUS "Setting default CMAKE_INSTALL_PREFIX path to ${CMAKE_BINARY_DIR}/install") 190 | set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install" CACHE STRING "The path to use for make install" FORCE) 191 | endif() 192 | ---- 193 | 194 | This example sets the default install location to under your build directory. 195 | 196 | [[destdir]] 197 | DESTDIR 198 | ^^^^^^^ 199 | 200 | If you wish to stage your install to confirm that all files are included the 201 | `make install` target supports the DESTDIR argument. 202 | 203 | ``` 204 | make install DESTDIR=/tmp/stage 205 | ``` 206 | 207 | This will create the install path `${DESTDIR}/${CMAKE_INSTALL_PREFIX}` for all 208 | your installation files. In this example, it would install all files under the 209 | path `/tmp/stage/usr/local` 210 | 211 | ``` 212 | $ tree /tmp/stage 213 | /tmp/stage 214 | └── usr 215 | └── local 216 | ├── bin 217 | │   └── cmake_examples_inst_bin 218 | ├── etc 219 | │   └── cmake-examples.conf 220 | └── lib 221 | └── libcmake_examples_inst.so 222 | ``` 223 | 224 | [[uninstall]] 225 | Uninstall 226 | ^^^^^^^^^ 227 | 228 | By default CMake does not add a `make uninstall` target. For details on how to generate 229 | an uninstall target see this https://cmake.org/Wiki/CMake_FAQ#Can_I_do_.22make_uninstall.22_with_CMake.3F[FAQ] 230 | 231 | For an easy way to remove the files from this example, you can use: 232 | 233 | ``` 234 | sudo xargs rm < install_manifest.txt 235 | ``` 236 | -------------------------------------------------------------------------------- /01-basic/E-installing/cmake-examples.conf: -------------------------------------------------------------------------------- 1 | # Sample configuration file that could be installed 2 | -------------------------------------------------------------------------------- /01-basic/E-installing/include/installing/Hello.h: -------------------------------------------------------------------------------- 1 | #ifndef __HELLO_H__ 2 | #define __HELLO_H__ 3 | 4 | class Hello 5 | { 6 | public: 7 | void print(); 8 | }; 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /01-basic/E-installing/src/Hello.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "installing/Hello.h" 4 | 5 | void Hello::print() 6 | { 7 | std::cout << "Hello Install!" << std::endl; 8 | } 9 | -------------------------------------------------------------------------------- /01-basic/E-installing/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "installing/Hello.h" 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | Hello hi; 6 | hi.print(); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /01-basic/F-build-type/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Set the minimum version of CMake that can be used 2 | # To find the cmake version run 3 | # $ cmake --version 4 | cmake_minimum_required(VERSION 3.5) 5 | 6 | # Set a default build type if none was specified 7 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) 8 | message("Setting build type to 'RelWithDebInfo' as none was specified.") 9 | set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE) 10 | # Set the possible values of build type for cmake-gui 11 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" 12 | "MinSizeRel" "RelWithDebInfo") 13 | endif() 14 | 15 | # Set the project name 16 | project (build_type) 17 | 18 | # Add an executable 19 | add_executable(cmake_examples_build_type main.cpp) 20 | -------------------------------------------------------------------------------- /01-basic/F-build-type/cmake-gui-build-type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttroy50/cmake-examples/2b27fc75c40447c8cf9b371cc21224dd96d6ce45/01-basic/F-build-type/cmake-gui-build-type.png -------------------------------------------------------------------------------- /01-basic/F-build-type/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | std::cout << "Hello Build Type!" << std::endl; 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /01-basic/G-compile-flags/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | # Set a default C++ compile flag 4 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEX2" CACHE STRING "Set C++ Compiler Flags" FORCE) 5 | 6 | # Set the project name 7 | project (compile_flags) 8 | 9 | # Add an executable 10 | add_executable(cmake_examples_compile_flags main.cpp) 11 | 12 | target_compile_definitions(cmake_examples_compile_flags 13 | PRIVATE EX3 14 | ) 15 | -------------------------------------------------------------------------------- /01-basic/G-compile-flags/README.adoc: -------------------------------------------------------------------------------- 1 | = Compile Flags 2 | :toc: 3 | :toc-placement!: 4 | 5 | toc::[] 6 | 7 | # Introduction 8 | 9 | CMake supports setting compile flags in a number of different ways: 10 | 11 | * using +target_compile_definitions()+ function 12 | * using the +CMAKE_C_FLAGS+ and +CMAKE_CXX_FLAGS+ variables. 13 | 14 | The files in this tutorial are below: 15 | 16 | ``` 17 | $ tree 18 | . 19 | ├── CMakeLists.txt 20 | ├── main.cpp 21 | ``` 22 | 23 | * link:CMakeLists.txt[] - Contains the CMake commands you wish to run 24 | * link:main.cpp[] - The source file with main 25 | 26 | # Concepts 27 | 28 | # Set Per-Target C++ Flags 29 | 30 | The recommended way to set C++ flags in modern CMake is to use per-target flags which can be populated to other targets 31 | through the +target_compile_definitions()+ link:https://cmake.org/cmake/help/v3.0/command/target_compile_definitions.html?highlight=target_compile_definitions[function]. This will populate the link:https://cmake.org/cmake/help/v3.0/prop_tgt/INTERFACE_COMPILE_DEFINITIONS.html#prop_tgt:INTERFACE_COMPILE_DEFINITIONS[INTERFACE_COMPILE_DEFINITIONS] for the library and push the definition to the linked target depending on the scope. 32 | 33 | [source,cmake] 34 | ---- 35 | target_compile_definitions(cmake_examples_compile_flags 36 | PRIVATE EX3 37 | ) 38 | ---- 39 | 40 | This will cause the compiler to add the definition +-DEX3+ when compiling the target. 41 | 42 | If the target was a library and the scope +PUBLIC+ or +INTERFACE+ has been chosen the definition would also be included in any executables that link this target. 43 | 44 | For compiler options you can also use the +target_compile_options()+ link:https://cmake.org/cmake/help/v3.0/command/target_compile_options.html[function]. 45 | 46 | ## Set Default C++ Flags 47 | 48 | The default `CMAKE_CXX_FLAGS` is either empty or contains the appropriate flags 49 | for the build type. 50 | 51 | To set additional default compile flags you can add the following to your 52 | top level CMakeLists.txt 53 | 54 | [source,cmake] 55 | ---- 56 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEX2" CACHE STRING "Set C++ Compiler Flags" FORCE) 57 | ---- 58 | 59 | Similarly to +CMAKE_CXX_FLAGS+ other options include: 60 | 61 | * Setting C compiler flags using +CMAKE_C_FLAGS+ 62 | * Setting linker flags using +CMAKE_LINKER_FLAGS+. 63 | 64 | [NOTE] 65 | ==== 66 | The values `CACHE STRING "Set C++ Compiler Flags" FORCE` from the above command 67 | are used to force this variable to be set in the CMakeCache.txt file. 68 | 69 | For more details, see https://cmake.org/cmake/help/v3.0/command/set.html[here] 70 | ==== 71 | 72 | 73 | Once set the +CMAKE_C_FLAGS+ and +CMAKE_CXX_FLAGS+ will set a compiler flag / definition globally for all targets in this directory or any included sub-directories. This method is not recommended for general usage now and the +target_compile_definitions+ function is preferred. 74 | 75 | ### Set CMake Flags 76 | 77 | Similar to the build type a global C++ compiler flag can be set using the following methods. 78 | 79 | - Using a gui tool such as ccmake / cmake-gui 80 | 81 | image::cmake-gui-set-cxx-flag.png[cmake-gui set cxx flag] 82 | 83 | - Passing into cmake 84 | 85 | [source,cmake] 86 | ---- 87 | cmake .. -DCMAKE_CXX_FLAGS="-DEX3" 88 | ---- 89 | 90 | # Building the Example 91 | 92 | [source,bash] 93 | ---- 94 | $ mkdir build 95 | 96 | $ cd build/ 97 | 98 | $ cmake .. 99 | -- The C compiler identification is GNU 4.8.4 100 | -- The CXX compiler identification is GNU 4.8.4 101 | -- Check for working C compiler: /usr/bin/cc 102 | -- Check for working C compiler: /usr/bin/cc -- works 103 | -- Detecting C compiler ABI info 104 | -- Detecting C compiler ABI info - done 105 | -- Check for working CXX compiler: /usr/bin/c++ 106 | -- Check for working CXX compiler: /usr/bin/c++ -- works 107 | -- Detecting CXX compiler ABI info 108 | -- Detecting CXX compiler ABI info - done 109 | -- Configuring done 110 | -- Generating done 111 | -- Build files have been written to: /home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build 112 | 113 | $ make VERBOSE=1 114 | /usr/bin/cmake -H/home/matrim/workspace/cmake-examples/01-basic/G-compile-flags -B/home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build --check-build-system CMakeFiles/Makefile.cmake 0 115 | /usr/bin/cmake -E cmake_progress_start /home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build/CMakeFiles /home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build/CMakeFiles/progress.marks 116 | make -f CMakeFiles/Makefile2 all 117 | make[1]: Entering directory `/home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build' 118 | make -f CMakeFiles/cmake_examples_compile_flags.dir/build.make CMakeFiles/cmake_examples_compile_flags.dir/depend 119 | make[2]: Entering directory `/home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build' 120 | cd /home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /home/matrim/workspace/cmake-examples/01-basic/G-compile-flags /home/matrim/workspace/cmake-examples/01-basic/G-compile-flags /home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build /home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build /home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build/CMakeFiles/cmake_examples_compile_flags.dir/DependInfo.cmake --color= 121 | Dependee "/home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build/CMakeFiles/cmake_examples_compile_flags.dir/DependInfo.cmake" is newer than depender "/home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build/CMakeFiles/cmake_examples_compile_flags.dir/depend.internal". 122 | Dependee "/home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build/CMakeFiles/CMakeDirectoryInformation.cmake" is newer than depender "/home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build/CMakeFiles/cmake_examples_compile_flags.dir/depend.internal". 123 | Scanning dependencies of target cmake_examples_compile_flags 124 | make[2]: Leaving directory `/home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build' 125 | make -f CMakeFiles/cmake_examples_compile_flags.dir/build.make CMakeFiles/cmake_examples_compile_flags.dir/build 126 | make[2]: Entering directory `/home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build' 127 | /usr/bin/cmake -E cmake_progress_report /home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build/CMakeFiles 1 128 | [100%] Building CXX object CMakeFiles/cmake_examples_compile_flags.dir/main.cpp.o 129 | /usr/bin/c++ -DEX2 -o CMakeFiles/cmake_examples_compile_flags.dir/main.cpp.o -c /home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/main.cpp 130 | Linking CXX executable cmake_examples_compile_flags 131 | /usr/bin/cmake -E cmake_link_script CMakeFiles/cmake_examples_compile_flags.dir/link.txt --verbose=1 132 | /usr/bin/c++ -DEX2 CMakeFiles/cmake_examples_compile_flags.dir/main.cpp.o -o cmake_examples_compile_flags -rdynamic 133 | make[2]: Leaving directory `/home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build' 134 | /usr/bin/cmake -E cmake_progress_report /home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build/CMakeFiles 1 135 | [100%] Built target cmake_examples_compile_flags 136 | make[1]: Leaving directory `/home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build' 137 | /usr/bin/cmake -E cmake_progress_start /home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build/CMakeFiles 0 138 | ---- 139 | -------------------------------------------------------------------------------- /01-basic/G-compile-flags/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | std::cout << "Hello Compile Flags!" << std::endl; 6 | 7 | // only print if compile flag set 8 | #ifdef EX2 9 | std::cout << "Hello Compile Flag EX2!" << std::endl; 10 | #endif 11 | 12 | #ifdef EX3 13 | std::cout << "Hello Compile Flag EX3!" << std::endl; 14 | #endif 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /01-basic/H-third-party-library/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | # Set the project name 4 | project (third_party_include) 5 | 6 | 7 | # find a boost install with the libraries filesystem and system 8 | find_package(Boost 1.46.1 REQUIRED COMPONENTS filesystem system) 9 | 10 | # check if boost was found 11 | if(Boost_FOUND) 12 | message ("boost found") 13 | else() 14 | message (FATAL_ERROR "Cannot find Boost") 15 | endif() 16 | 17 | # Add an executable 18 | add_executable(third_party_include main.cpp) 19 | 20 | # link against the boost libraries 21 | target_link_libraries( third_party_include 22 | PRIVATE 23 | Boost::filesystem 24 | ) 25 | -------------------------------------------------------------------------------- /01-basic/H-third-party-library/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | std::cout << "Hello Third Party Include!" << std::endl; 8 | 9 | // use a shared ptr 10 | boost::shared_ptr isp(new int(4)); 11 | 12 | // trivial use of boost filesystem 13 | boost::filesystem::path path = "/usr/share/cmake/modules"; 14 | if(path.is_relative()) 15 | { 16 | std::cout << "Path is relative" << std::endl; 17 | } 18 | else 19 | { 20 | std::cout << "Path is not relative" << std::endl; 21 | } 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /01-basic/I-compiling-with-clang/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Set the minimum version of CMake that can be used 2 | # To find the cmake version run 3 | # $ cmake --version 4 | cmake_minimum_required(VERSION 3.5) 5 | 6 | # Set the project name 7 | project (hello_cmake) 8 | 9 | # Add an executable 10 | add_executable(hello_cmake main.cpp) 11 | -------------------------------------------------------------------------------- /01-basic/I-compiling-with-clang/README.adoc: -------------------------------------------------------------------------------- 1 | = Compiling with clang 2 | :toc: 3 | :toc-placement!: 4 | 5 | toc::[] 6 | 7 | # Introduction 8 | 9 | When building with CMake it is possible to set the C and C++ compiler. This example 10 | is the same as the link:../A-hello-cmake[hello-cmake] example except that it shows the most basic 11 | method of changing the compiler from the default gcc to http://clang.llvm.org/[clang]. 12 | 13 | The files in this tutorial are below: 14 | 15 | ``` 16 | $ tree 17 | . 18 | ├── CMakeLists.txt 19 | ├── main.cpp 20 | ``` 21 | 22 | * link:CMakeLists.txt[] - Contains the CMake commands you wish to run 23 | * link:main.cpp[] - A simple "Hello World" cpp file. 24 | 25 | # Concepts 26 | 27 | ### Compiler Option 28 | 29 | CMake exposes options to control the programs used to compile and link your code. These 30 | programs include: 31 | 32 | * CMAKE_C_COMPILER - The program used to compile c code. 33 | * CMAKE_CXX_COMPILER - The program used to compile c++ code. 34 | * CMAKE_LINKER - The program used to link your binary. 35 | 36 | [NOTE] 37 | ==== 38 | In this example clang-3.6 is installed via the command `sudo apt-get install clang-3.6` 39 | ==== 40 | 41 | [NOTE] 42 | ==== 43 | This is the most basic and easiest way to invoke clang. Future examples will show better 44 | ways to invoke the compiler. 45 | ==== 46 | 47 | 48 | ### Setting Flags 49 | 50 | As described in the link:../F-build-type[Build Type] example, you can set CMake options 51 | using either a cmake gui or by passing from the command line. 52 | 53 | Below is an example of passing the compiler via the command line. 54 | 55 | [source,cmake] 56 | ---- 57 | cmake .. -DCMAKE_C_COMPILER=clang-3.6 -DCMAKE_CXX_COMPILER=clang++-3.6 58 | ---- 59 | 60 | After setting these options, when your run `make` clang will be used to compile your binary. This 61 | can be seen from the following lines in the make output. 62 | 63 | [source,bash] 64 | ---- 65 | /usr/bin/clang++-3.6 -o CMakeFiles/hello_cmake.dir/main.cpp.o -c /home/matrim/workspace/cmake-examples/01-basic/I-compiling-with-clang/main.cpp 66 | Linking CXX executable hello_cmake 67 | /usr/bin/cmake -E cmake_link_script CMakeFiles/hello_cmake.dir/link.txt --verbose=1 68 | /usr/bin/clang++-3.6 CMakeFiles/hello_cmake.dir/main.cpp.o -o hello_cmake -rdynamic 69 | ---- 70 | 71 | 72 | 73 | # Building the Examples 74 | 75 | Below is sample output from building this example. 76 | 77 | [source,bash] 78 | ---- 79 | $ mkdir build.clang 80 | 81 | $ cd build.clang/ 82 | 83 | $ cmake .. -DCMAKE_C_COMPILER=clang-3.6 -DCMAKE_CXX_COMPILER=clang++-3.6 84 | -- The C compiler identification is Clang 3.6.0 85 | -- The CXX compiler identification is Clang 3.6.0 86 | -- Check for working C compiler: /usr/bin/clang-3.6 87 | -- Check for working C compiler: /usr/bin/clang-3.6 -- works 88 | -- Detecting C compiler ABI info 89 | -- Detecting C compiler ABI info - done 90 | -- Check for working CXX compiler: /usr/bin/clang++-3.6 91 | -- Check for working CXX compiler: /usr/bin/clang++-3.6 -- works 92 | -- Detecting CXX compiler ABI info 93 | -- Detecting CXX compiler ABI info - done 94 | -- Configuring done 95 | -- Generating done 96 | -- Build files have been written to: /home/matrim/workspace/cmake-examples/01-basic/I-compiling-with-clang/build.clang 97 | 98 | $ make VERBOSE=1 99 | /usr/bin/cmake -H/home/matrim/workspace/cmake-examples/01-basic/I-compiling-with-clang -B/home/matrim/workspace/cmake-examples/01-basic/I-compiling-with-clang/build.clang --check-build-system CMakeFiles/Makefile.cmake 0 100 | /usr/bin/cmake -E cmake_progress_start /home/matrim/workspace/cmake-examples/01-basic/I-compiling-with-clang/build.clang/CMakeFiles /home/matrim/workspace/cmake-examples/01-basic/I-compiling-with-clang/build.clang/CMakeFiles/progress.marks 101 | make -f CMakeFiles/Makefile2 all 102 | make[1]: Entering directory `/home/matrim/workspace/cmake-examples/01-basic/I-compiling-with-clang/build.clang' 103 | make -f CMakeFiles/hello_cmake.dir/build.make CMakeFiles/hello_cmake.dir/depend 104 | make[2]: Entering directory `/home/matrim/workspace/cmake-examples/01-basic/I-compiling-with-clang/build.clang' 105 | cd /home/matrim/workspace/cmake-examples/01-basic/I-compiling-with-clang/build.clang && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /home/matrim/workspace/cmake-examples/01-basic/I-compiling-with-clang /home/matrim/workspace/cmake-examples/01-basic/I-compiling-with-clang /home/matrim/workspace/cmake-examples/01-basic/I-compiling-with-clang/build.clang /home/matrim/workspace/cmake-examples/01-basic/I-compiling-with-clang/build.clang /home/matrim/workspace/cmake-examples/01-basic/I-compiling-with-clang/build.clang/CMakeFiles/hello_cmake.dir/DependInfo.cmake --color= 106 | Dependee "/home/matrim/workspace/cmake-examples/01-basic/I-compiling-with-clang/build.clang/CMakeFiles/hello_cmake.dir/DependInfo.cmake" is newer than depender "/home/matrim/workspace/cmake-examples/01-basic/I-compiling-with-clang/build.clang/CMakeFiles/hello_cmake.dir/depend.internal". 107 | Dependee "/home/matrim/workspace/cmake-examples/01-basic/I-compiling-with-clang/build.clang/CMakeFiles/CMakeDirectoryInformation.cmake" is newer than depender "/home/matrim/workspace/cmake-examples/01-basic/I-compiling-with-clang/build.clang/CMakeFiles/hello_cmake.dir/depend.internal". 108 | Scanning dependencies of target hello_cmake 109 | make[2]: Leaving directory `/home/matrim/workspace/cmake-examples/01-basic/I-compiling-with-clang/build.clang' 110 | make -f CMakeFiles/hello_cmake.dir/build.make CMakeFiles/hello_cmake.dir/build 111 | make[2]: Entering directory `/home/matrim/workspace/cmake-examples/01-basic/I-compiling-with-clang/build.clang' 112 | /usr/bin/cmake -E cmake_progress_report /home/matrim/workspace/cmake-examples/01-basic/I-compiling-with-clang/build.clang/CMakeFiles 1 113 | [100%] Building CXX object CMakeFiles/hello_cmake.dir/main.cpp.o 114 | /usr/bin/clang++-3.6 -o CMakeFiles/hello_cmake.dir/main.cpp.o -c /home/matrim/workspace/cmake-examples/01-basic/I-compiling-with-clang/main.cpp 115 | Linking CXX executable hello_cmake 116 | /usr/bin/cmake -E cmake_link_script CMakeFiles/hello_cmake.dir/link.txt --verbose=1 117 | /usr/bin/clang++-3.6 CMakeFiles/hello_cmake.dir/main.cpp.o -o hello_cmake -rdynamic 118 | make[2]: Leaving directory `/home/matrim/workspace/cmake-examples/01-basic/I-compiling-with-clang/build.clang' 119 | /usr/bin/cmake -E cmake_progress_report /home/matrim/workspace/cmake-examples/01-basic/I-compiling-with-clang/build.clang/CMakeFiles 1 120 | [100%] Built target hello_cmake 121 | make[1]: Leaving directory `/home/matrim/workspace/cmake-examples/01-basic/I-compiling-with-clang/build.clang' 122 | /usr/bin/cmake -E cmake_progress_start /home/matrim/workspace/cmake-examples/01-basic/I-compiling-with-clang/build.clang/CMakeFiles 0 123 | 124 | $ ./hello_cmake 125 | Hello CMake! 126 | ---- 127 | -------------------------------------------------------------------------------- /01-basic/I-compiling-with-clang/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | std::cout << "Hello CMake!" << std::endl; 6 | return 0; 7 | } -------------------------------------------------------------------------------- /01-basic/I-compiling-with-clang/pre_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ROOT_DIR=`pwd` 4 | dir="01-basic/I-compiling-with-clang" 5 | 6 | if [ -d "$ROOT_DIR/$dir/build.clang" ]; then 7 | echo "deleting $dir/build.clang" 8 | rm -r $dir/build.clang 9 | fi 10 | -------------------------------------------------------------------------------- /01-basic/I-compiling-with-clang/run_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Ubuntu supports multiple versions of clang to be installed at the same time. 3 | # The tests need to determine the clang binary before calling cmake 4 | clang_bin=`which clang` 5 | clang_xx_bin=`which clang++` 6 | 7 | if [ -z $clang_bin ]; then 8 | clang_ver=`dpkg --get-selections | grep clang | grep -v -m1 libclang | cut -f1 | cut -d '-' -f2` 9 | clang_bin="clang-$clang_ver" 10 | clang_xx_bin="clang++-$clang_ver" 11 | fi 12 | 13 | echo "Will use clang [$clang_bin] and clang++ [$clang_xx_bin]" 14 | 15 | 16 | mkdir -p build.clang && cd build.clang && \ 17 | cmake .. -DCMAKE_C_COMPILER=$clang_bin -DCMAKE_CXX_COMPILER=$clang_xx_bin && make 18 | -------------------------------------------------------------------------------- /01-basic/J-building-with-ninja/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Set the minimum version of CMake that can be used 2 | # To find the cmake version run 3 | # $ cmake --version 4 | cmake_minimum_required(VERSION 3.5) 5 | 6 | # Set the project name 7 | project (hello_cmake) 8 | 9 | # Add an executable 10 | add_executable(hello_cmake main.cpp) 11 | -------------------------------------------------------------------------------- /01-basic/J-building-with-ninja/README.adoc: -------------------------------------------------------------------------------- 1 | = Building with ninja 2 | :toc: 3 | :toc-placement!: 4 | 5 | toc::[] 6 | 7 | # Introduction 8 | 9 | As mentioned, CMake is a meta-build system that can be used to 10 | create the build files for many other build tools. This example shows how 11 | to have CMake use the https://ninja-build.org/[ninja build] tool. 12 | 13 | The files in this tutorial are below: 14 | 15 | ``` 16 | $ tree 17 | . 18 | ├── CMakeLists.txt 19 | ├── main.cpp 20 | ``` 21 | 22 | * link:CMakeLists.txt[] - Contains the CMake commands you wish to run 23 | * link:main.cpp[] - A simple "Hello World" cpp file. 24 | 25 | # Concepts 26 | 27 | ### Generators 28 | 29 | CMake https://cmake.org/cmake/help/v3.0/manual/cmake-generators.7.html[generators] are 30 | responsible for writing the input files (e.g. Makefiles) for the underlying build system. Running `cmake --help` 31 | will show the generators available. For cmake v2.8.12.2 the generators supported 32 | on my system include: 33 | 34 | [source,bash] 35 | ---- 36 | Generators 37 | 38 | The following generators are available on this platform: 39 | Unix Makefiles = Generates standard UNIX makefiles. 40 | Ninja = Generates build.ninja files (experimental). 41 | CodeBlocks - Ninja = Generates CodeBlocks project files. 42 | CodeBlocks - Unix Makefiles = Generates CodeBlocks project files. 43 | Eclipse CDT4 - Ninja = Generates Eclipse CDT 4.0 project files. 44 | Eclipse CDT4 - Unix Makefiles 45 | = Generates Eclipse CDT 4.0 project files. 46 | KDevelop3 = Generates KDevelop 3 project files. 47 | KDevelop3 - Unix Makefiles = Generates KDevelop 3 project files. 48 | Sublime Text 2 - Ninja = Generates Sublime Text 2 project files. 49 | Sublime Text 2 - Unix Makefiles 50 | = Generates Sublime Text 2 project files.Generators 51 | ---- 52 | 53 | As specified in this https://stackoverflow.com/questions/25941536/what-is-a-cmake-generator[post], 54 | CMake includes different types of generators such as Command-Line, IDE, and Extra generators. 55 | 56 | #### Command-Line Build Tool Generators 57 | 58 | These generators are for command-line build tools, like Make and Ninja. The chosen tool chain must be configured prior to generating the build system with CMake. 59 | 60 | The supported generators include: 61 | 62 | * Borland Makefiles 63 | * MSYS Makefiles 64 | * MinGW Makefiles 65 | * NMake Makefiles 66 | * NMake Makefiles JOM 67 | * Ninja 68 | * Unix Makefiles 69 | * Watcom WMake 70 | 71 | #### IDE Build Tool Generators 72 | 73 | These generators are for Integrated Development Environments that include their own compiler. Examples are Visual Studio and Xcode which include a compiler natively. 74 | 75 | The supported generators include: 76 | 77 | * Visual Studio 6 78 | * Visual Studio 7 79 | * Visual Studio 7 .NET 2003 80 | * Visual Studio 8 2005 81 | * Visual Studio 9 2008 82 | * Visual Studio 10 2010 83 | * Visual Studio 11 2012 84 | * Visual Studio 12 2013 85 | * Xcode 86 | 87 | #### Extra Generators 88 | 89 | These are generators create a configuration to work with an alternative IDE tool and must be included with either an IDE or Command-Line generator. 90 | 91 | The supported generators include: 92 | 93 | * CodeBlocks 94 | * CodeLite 95 | * Eclipse CDT4 96 | * KDevelop3 97 | * Kate 98 | * Sublime Text 2 99 | 100 | 101 | [NOTE] 102 | ==== 103 | In this example ninja is installed via the command `sudo apt-get install ninja-build` 104 | ==== 105 | 106 | ### Calling a Generator 107 | 108 | To call a CMake generator you can use the `-G` command line switch, for example: 109 | 110 | [source,cmake] 111 | ---- 112 | cmake .. -G Ninja 113 | ---- 114 | 115 | After doing the above CMake will generate the required Ninja build files, which can be run 116 | from using the `ninja` command. 117 | 118 | [source,bash] 119 | ---- 120 | $ cmake .. -G Ninja 121 | 122 | $ ls 123 | build.ninja CMakeCache.txt CMakeFiles cmake_install.cmake rules.ninja 124 | ---- 125 | 126 | # Building the Examples 127 | 128 | Below is sample output from building this example. 129 | 130 | [source,bash] 131 | ---- 132 | $ mkdir build.ninja 133 | 134 | $ cd build.ninja/ 135 | 136 | $ cmake .. -G Ninja 137 | -- The C compiler identification is GNU 4.8.4 138 | -- The CXX compiler identification is GNU 4.8.4 139 | -- Check for working C compiler using: Ninja 140 | -- Check for working C compiler using: Ninja -- works 141 | -- Detecting C compiler ABI info 142 | -- Detecting C compiler ABI info - done 143 | -- Check for working CXX compiler using: Ninja 144 | -- Check for working CXX compiler using: Ninja -- works 145 | -- Detecting CXX compiler ABI info 146 | -- Detecting CXX compiler ABI info - done 147 | -- Configuring done 148 | -- Generating done 149 | -- Build files have been written to: /home/matrim/workspace/cmake-examples/01-basic/J-building-with-ninja/build.ninja 150 | 151 | $ ninja -v 152 | [1/2] /usr/bin/c++ -MMD -MT CMakeFiles/hello_cmake.dir/main.cpp.o -MF "CMakeFiles/hello_cmake.dir/main.cpp.o.d" -o CMakeFiles/hello_cmake.dir/main.cpp.o -c ../main.cpp 153 | [2/2] : && /usr/bin/c++ CMakeFiles/hello_cmake.dir/main.cpp.o -o hello_cmake -rdynamic && : 154 | 155 | $ ls 156 | build.ninja CMakeCache.txt CMakeFiles cmake_install.cmake hello_cmake rules.ninja 157 | 158 | $ ./hello_cmake 159 | Hello CMake! 160 | ---- 161 | -------------------------------------------------------------------------------- /01-basic/J-building-with-ninja/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | std::cout << "Hello CMake!" << std::endl; 6 | return 0; 7 | } -------------------------------------------------------------------------------- /01-basic/J-building-with-ninja/pre_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ROOT_DIR=`pwd` 4 | dir="01-basic/J-building-with-ninja" 5 | 6 | if [ -d "$ROOT_DIR/$dir/build.ninja" ]; then 7 | echo "deleting $dir/build.ninja" 8 | rm -r $dir/build.ninja 9 | fi 10 | -------------------------------------------------------------------------------- /01-basic/J-building-with-ninja/run_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Travis-ci cmake version doesn't support ninja, so first check if it's supported 3 | ninja_supported=`cmake --help | grep Ninja` 4 | 5 | if [ -z $ninja_supported ]; then 6 | echo "Ninja not supported" 7 | exit 8 | fi 9 | 10 | mkdir -p build.ninja && cd build.ninja && \ 11 | cmake .. -G Ninja && ninja 12 | -------------------------------------------------------------------------------- /01-basic/K-imported-targets/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | # Set the project name 4 | project (imported_targets) 5 | 6 | 7 | # find a boost install with the libraries filesystem and system 8 | find_package(Boost 1.46.1 REQUIRED COMPONENTS filesystem system) 9 | 10 | # check if boost was found 11 | if(Boost_FOUND) 12 | message ("boost found") 13 | else() 14 | message (FATAL_ERROR "Cannot find Boost") 15 | endif() 16 | 17 | # Add an executable 18 | add_executable(imported_targets main.cpp) 19 | 20 | # link against the boost libraries 21 | target_link_libraries( imported_targets 22 | PRIVATE 23 | Boost::filesystem 24 | ) 25 | -------------------------------------------------------------------------------- /01-basic/K-imported-targets/README.adoc: -------------------------------------------------------------------------------- 1 | = Imported Targets 2 | :toc: 3 | :toc-placement!: 4 | 5 | toc::[] 6 | 7 | # Introduction 8 | 9 | As previously mentioned in the link:../H-third-party-library[third party library], newer 10 | versions of CMake allow you to link third party libraries using link:https://cmake.org/cmake/help/v3.6/prop_tgt/IMPORTED.html#prop_tgt:IMPORTED[imported] +ALIAS+ targets. 11 | 12 | The files in this tutorial are below: 13 | 14 | ``` 15 | $ tree 16 | . 17 | ├── CMakeLists.txt 18 | ├── main.cpp 19 | ``` 20 | 21 | * link:CMakeLists.txt[] - Contains the CMake commands you wish to run 22 | * link:main.cpp[] - The source file with main 23 | 24 | # Requirements 25 | 26 | This example requires the following: 27 | 28 | * CMake v3.5+ 29 | * The boost libraries to be installed in a default system location. 30 | 31 | # Concepts 32 | 33 | ## Imported Target 34 | 35 | Imported targets are read-only targets that are exported by FindXXX modules. 36 | 37 | To include boost filesystem you can do the following: 38 | 39 | [source,cmake] 40 | ---- 41 | target_link_libraries( imported_targets 42 | PRIVATE 43 | Boost::filesystem 44 | ) 45 | ---- 46 | 47 | This will automtaically link the Boost::filesystem and Boost::system libraries while also including the 48 | Boost include directories. 49 | 50 | # Building the Example 51 | 52 | [source,bash] 53 | ---- 54 | $ mkdir build 55 | 56 | $ cd build/ 57 | 58 | $ cmake .. 59 | -- The C compiler identification is GNU 5.4.0 60 | -- The CXX compiler identification is GNU 5.4.0 61 | -- Check for working C compiler: /usr/bin/cc 62 | -- Check for working C compiler: /usr/bin/cc -- works 63 | -- Detecting C compiler ABI info 64 | -- Detecting C compiler ABI info - done 65 | -- Detecting C compile features 66 | -- Detecting C compile features - done 67 | -- Check for working CXX compiler: /usr/bin/c++ 68 | -- Check for working CXX compiler: /usr/bin/c++ -- works 69 | -- Detecting CXX compiler ABI info 70 | -- Detecting CXX compiler ABI info - done 71 | -- Detecting CXX compile features 72 | -- Detecting CXX compile features - done 73 | -- Boost version: 1.58.0 74 | -- Found the following Boost libraries: 75 | -- filesystem 76 | -- system 77 | boost found 78 | -- Configuring done 79 | -- Generating done 80 | -- Build files have been written to: /data/code/01-basic/K-imported-targets/build 81 | 82 | $ make 83 | Scanning dependencies of target imported_targets 84 | [ 50%] Building CXX object CMakeFiles/imported_targets.dir/main.cpp.o 85 | [100%] Linking CXX executable imported_targets 86 | [100%] Built target imported_targets 87 | 88 | 89 | $ ./imported_targets 90 | Hello Third Party Include! 91 | Path is not relative 92 | 93 | 94 | ---- 95 | -------------------------------------------------------------------------------- /01-basic/K-imported-targets/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | std::cout << "Hello Third Party Include!" << std::endl; 8 | 9 | // use a shared ptr 10 | boost::shared_ptr isp(new int(4)); 11 | 12 | // trivial use of boost filesystem 13 | boost::filesystem::path path = "/usr/share/cmake/modules"; 14 | if(path.is_relative()) 15 | { 16 | std::cout << "Path is relative" << std::endl; 17 | } 18 | else 19 | { 20 | std::cout << "Path is not relative" << std::endl; 21 | } 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /01-basic/K-imported-targets/run_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Make sure we have the minimum cmake version 3 | cmake_version=`cmake --version | grep version | cut -d" " -f3` 4 | 5 | [[ "$cmake_version" =~ ([3-9][.][5-9.][.][0-9]) ]] || exit 0 6 | 7 | echo "correct version of cmake" 8 | mkdir -p build && cd build && cmake .. && make 9 | if [ $? -ne 0 ]; then 10 | echo "Error running example" 11 | exit 1 12 | fi 13 | -------------------------------------------------------------------------------- /01-basic/L-cpp-standard/README.adoc: -------------------------------------------------------------------------------- 1 | = C++ Standard 2 | 3 | Since the release of C+\+11 and C++14 a common use case is to invoke the compiler to use these standards. As CMake has evolved, it has added features to make this easier and new versions of CMake have changed how this is achieved. 4 | 5 | The following examples show different methods of setting the C++ standard and what versions of CMake they are available from. 6 | 7 | The examples include: 8 | 9 | - link:i-common-method[common-method]. A simple version that should work with most versions of CMake. 10 | - link:ii-cxx-standard[cxx-standard]. Using the `CMAKE_CXX_STANDARD` variable introduced in CMake v3.1. 11 | - link:iii-compile-features[compile-features]. Using the `target_compile_features` function introduced in CMake v3.1. 12 | -------------------------------------------------------------------------------- /01-basic/L-cpp-standard/i-common-method/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Set the minimum version of CMake that can be used 2 | # To find the cmake version run 3 | # $ cmake --version 4 | cmake_minimum_required(VERSION 2.8) 5 | 6 | # Set the project name 7 | project (hello_cpp11) 8 | 9 | # try conditional compilation 10 | include(CheckCXXCompilerFlag) 11 | CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) 12 | CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X) 13 | 14 | # check results and add flag 15 | if(COMPILER_SUPPORTS_CXX11)# 16 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 17 | elseif(COMPILER_SUPPORTS_CXX0X)# 18 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") 19 | else() 20 | message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.") 21 | endif() 22 | 23 | # Add an executable 24 | add_executable(hello_cpp11 main.cpp) 25 | -------------------------------------------------------------------------------- /01-basic/L-cpp-standard/i-common-method/README.adoc: -------------------------------------------------------------------------------- 1 | = C++ Standard Common Method 2 | :toc: 3 | :toc-placement!: 4 | 5 | toc::[] 6 | 7 | # Introduction 8 | 9 | This example shows a common method to set the C++ Standard. This can be used with most versions of CMake. However, if you are targeting a recent version of CMake there are more convenient methods available. 10 | 11 | The files in this tutorial are below: 12 | 13 | ``` 14 | A-hello-cmake$ tree 15 | . 16 | ├── CMakeLists.txt 17 | ├── main.cpp 18 | ``` 19 | 20 | * link:CMakeLists.txt[CMakeLists.txt] - Contains the CMake commands you wish to run 21 | * link:main.cpp[main.cpp] - A simple "Hello World" cpp file targeting C++11. 22 | 23 | # Concepts 24 | 25 | ## Checking Compile flags 26 | 27 | CMake has support for attempting to compile a program with any flags you pass into the function `CMAKE_CXX_COMPILER_FLAG`. The result is then stored in a variable that you pass in. 28 | 29 | For example: 30 | 31 | [source,cmake] 32 | ---- 33 | include(CheckCXXCompilerFlag) 34 | CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) 35 | ---- 36 | 37 | This example will attempt to compile a program with the flag `-std=c++11` and store the result in the variable `COMPILER_SUPPORTS_CXX11`. 38 | 39 | The line `include(CheckCXXCompilerFlag)` tells CMake to include this function to make it available for use. 40 | 41 | ## Adding the flag 42 | 43 | Once you have determined if the compile supports a flag, you can then use the link:../../G-compile-flags/[standard cmake methods] to add this flag to a target. In this example we use the `CMAKE_CXX_FLAGS` to propegate the flag to all targets . 44 | 45 | [source,cmake] 46 | ---- 47 | if(COMPILER_SUPPORTS_CXX11)# 48 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 49 | elseif(COMPILER_SUPPORTS_CXX0X)# 50 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") 51 | else() 52 | message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.") 53 | endif() 54 | ---- 55 | 56 | The above example only checks for the gcc version of the compile flags and supports fallback from C+\+11 to the pre-standardisation C+\+0x flag. In real usage you may want to check for C++14, or add support for different methods of setting the compile, e.g. `-std=gnu++11` 57 | 58 | # Building the Examples 59 | 60 | Below is sample output from building this example. 61 | 62 | [source,bash] 63 | ---- 64 | $ mkdir build 65 | $ cd build 66 | 67 | $ cmake .. 68 | -- The C compiler identification is GNU 4.8.4 69 | -- The CXX compiler identification is GNU 4.8.4 70 | -- Check for working C compiler: /usr/bin/cc 71 | -- Check for working C compiler: /usr/bin/cc -- works 72 | -- Detecting C compiler ABI info 73 | -- Detecting C compiler ABI info - done 74 | -- Check for working CXX compiler: /usr/bin/c++ 75 | -- Check for working CXX compiler: /usr/bin/c++ -- works 76 | -- Detecting CXX compiler ABI info 77 | -- Detecting CXX compiler ABI info - done 78 | -- Performing Test COMPILER_SUPPORTS_CXX11 79 | -- Performing Test COMPILER_SUPPORTS_CXX11 - Success 80 | -- Performing Test COMPILER_SUPPORTS_CXX0X 81 | -- Performing Test COMPILER_SUPPORTS_CXX0X - Success 82 | -- Configuring done 83 | -- Generating done 84 | -- Build files have been written to: /data/code/01-basic/L-cpp-standard/i-common-method/build 85 | 86 | $ make VERBOSE=1 87 | /usr/bin/cmake -H/data/code/01-basic/L-cpp-standard/i-common-method -B/data/code/01-basic/L-cpp-standard/i-common-method/build --check-build-system CMakeFiles/Makefile.cmake 0 88 | /usr/bin/cmake -E cmake_progress_start /data/code/01-basic/L-cpp-standard/i-common-method/build/CMakeFiles /data/code/01-basic/L-cpp-standard/i-common-method/build/CMakeFiles/progress.marks 89 | make -f CMakeFiles/Makefile2 all 90 | make[1]: Entering directory `/data/code/01-basic/L-cpp-standard/i-common-method/build' 91 | make -f CMakeFiles/hello_cpp11.dir/build.make CMakeFiles/hello_cpp11.dir/depend 92 | make[2]: Entering directory `/data/code/01-basic/L-cpp-standard/i-common-method/build' 93 | cd /data/code/01-basic/L-cpp-standard/i-common-method/build && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /data/code/01-basic/L-cpp-standard/i-common-method /data/code/01-basic/L-cpp-standard/i-common-method /data/code/01-basic/L-cpp-standard/i-common-method/build /data/code/01-basic/L-cpp-standard/i-common-method/build /data/code/01-basic/L-cpp-standard/i-common-method/build/CMakeFiles/hello_cpp11.dir/DependInfo.cmake --color= 94 | Dependee "/data/code/01-basic/L-cpp-standard/i-common-method/build/CMakeFiles/hello_cpp11.dir/DependInfo.cmake" is newer than depender "/data/code/01-basic/L-cpp-standard/i-common-method/build/CMakeFiles/hello_cpp11.dir/depend.internal". 95 | Dependee "/data/code/01-basic/L-cpp-standard/i-common-method/build/CMakeFiles/CMakeDirectoryInformation.cmake" is newer than depender "/data/code/01-basic/L-cpp-standard/i-common-method/build/CMakeFiles/hello_cpp11.dir/depend.internal". 96 | Scanning dependencies of target hello_cpp11 97 | make[2]: Leaving directory `/data/code/01-basic/L-cpp-standard/i-common-method/build' 98 | make -f CMakeFiles/hello_cpp11.dir/build.make CMakeFiles/hello_cpp11.dir/build 99 | make[2]: Entering directory `/data/code/01-basic/L-cpp-standard/i-common-method/build' 100 | /usr/bin/cmake -E cmake_progress_report /data/code/01-basic/L-cpp-standard/i-common-method/build/CMakeFiles 1 101 | [100%] Building CXX object CMakeFiles/hello_cpp11.dir/main.cpp.o 102 | /usr/bin/c++ -std=c++11 -o CMakeFiles/hello_cpp11.dir/main.cpp.o -c /data/code/01-basic/L-cpp-standard/i-common-method/main.cpp 103 | Linking CXX executable hello_cpp11 104 | /usr/bin/cmake -E cmake_link_script CMakeFiles/hello_cpp11.dir/link.txt --verbose=1 105 | /usr/bin/c++ -std=c++11 CMakeFiles/hello_cpp11.dir/main.cpp.o -o hello_cpp11 -rdynamic 106 | make[2]: Leaving directory `/data/code/01-basic/L-cpp-standard/i-common-method/build' 107 | /usr/bin/cmake -E cmake_progress_report /data/code/01-basic/L-cpp-standard/i-common-method/build/CMakeFiles 1 108 | [100%] Built target hello_cpp11 109 | make[1]: Leaving directory `/data/code/01-basic/L-cpp-standard/i-common-method/build' 110 | /usr/bin/cmake -E cmake_progress_start /data/code/01-basic/L-cpp-standard/i-common-method/build/CMakeFiles 0 111 | ---- 112 | -------------------------------------------------------------------------------- /01-basic/L-cpp-standard/i-common-method/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | auto message = "Hello C++11"; 6 | std::cout << message << std::endl; 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /01-basic/L-cpp-standard/ii-cxx-standard/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Set the minimum version of CMake that can be used 2 | # To find the cmake version run 3 | # $ cmake --version 4 | cmake_minimum_required(VERSION 3.1) 5 | 6 | # Set the project name 7 | project (hello_cpp11) 8 | 9 | # set the C++ standard to C++ 11 10 | set(CMAKE_CXX_STANDARD 11) 11 | 12 | # Add an executable 13 | add_executable(hello_cpp11 main.cpp) 14 | -------------------------------------------------------------------------------- /01-basic/L-cpp-standard/ii-cxx-standard/README.adoc: -------------------------------------------------------------------------------- 1 | = Set C++ Standard 2 | :toc: 3 | :toc-placement!: 4 | 5 | toc::[] 6 | 7 | # Introduction 8 | 9 | This example shows how to set the C++ standard using the `CMAKE_CXX_STANDARD` variable. This is available since CMake v3.1 10 | 11 | The files in this tutorial are below: 12 | 13 | ``` 14 | A-hello-cmake$ tree 15 | . 16 | ├── CMakeLists.txt 17 | ├── main.cpp 18 | ``` 19 | 20 | * link:CMakeLists.txt[CMakeLists.txt] - Contains the CMake commands you wish to run 21 | * link:main.cpp[main.cpp] - A simple "Hello World" cpp file targeting C++11. 22 | 23 | # Concepts 24 | 25 | ## Using CXX_STANDARD property 26 | 27 | Setting the link:https://cmake.org/cmake/help/v3.1/variable/CMAKE_CXX_STANDARD.html[CMAKE_CXX_STANDARD] variable causes the `CXX_STANDARD` property on all targets. This causes CMake to set the appropriate flag at compille time. 28 | 29 | 30 | [NOTE] 31 | ==== 32 | The `CMAKE_CXX_STANDARD` variable falls back to the closest appropriate standard without a failure. For example, if you request `-std=gnu++11` you may end up with `-std=gnu++0x`. 33 | 34 | This can result in an unexpected failure at compile time. 35 | ==== 36 | 37 | # Building the Examples 38 | 39 | Below is sample output from building this example. 40 | 41 | [source,bash] 42 | ---- 43 | $ mkdir build 44 | $ cd build 45 | 46 | 47 | $ cmake .. 48 | -- The C compiler identification is GNU 5.4.0 49 | -- The CXX compiler identification is GNU 5.4.0 50 | -- Check for working C compiler: /usr/bin/cc 51 | -- Check for working C compiler: /usr/bin/cc -- works 52 | -- Detecting C compiler ABI info 53 | -- Detecting C compiler ABI info - done 54 | -- Detecting C compile features 55 | -- Detecting C compile features - done 56 | -- Check for working CXX compiler: /usr/bin/c++ 57 | -- Check for working CXX compiler: /usr/bin/c++ -- works 58 | -- Detecting CXX compiler ABI info 59 | -- Detecting CXX compiler ABI info - done 60 | -- Detecting CXX compile features 61 | -- Detecting CXX compile features - done 62 | -- Configuring done 63 | -- Generating done 64 | -- Build files have been written to: /data/code/01-basic/L-cpp-standard/ii-cxx-standard/build 65 | 66 | $ make VERBOSE=1 67 | /usr/bin/cmake -H/data/code/01-basic/L-cpp-standard/ii-cxx-standard -B/data/code/01-basic/L-cpp-standard/ii-cxx-standard/build --check-build-system CMakeFiles/Makefile.cmake 0 68 | /usr/bin/cmake -E cmake_progress_start /data/code/01-basic/L-cpp-standard/ii-cxx-standard/build/CMakeFiles /data/code/01-basic/L-cpp-standard/ii-cxx-standard/build/CMakeFiles/progress.marks 69 | make -f CMakeFiles/Makefile2 all 70 | make[1]: Entering directory '/data/code/01-basic/L-cpp-standard/ii-cxx-standard/build' 71 | make -f CMakeFiles/hello_cpp11.dir/build.make CMakeFiles/hello_cpp11.dir/depend 72 | make[2]: Entering directory '/data/code/01-basic/L-cpp-standard/ii-cxx-standard/build' 73 | cd /data/code/01-basic/L-cpp-standard/ii-cxx-standard/build && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /data/code/01-basic/L-cpp-standard/ii-cxx-standard /data/code/01-basic/L-cpp-standard/ii-cxx-standard /data/code/01-basic/L-cpp-standard/ii-cxx-standard/build /data/code/01-basic/L-cpp-standard/ii-cxx-standard/build /data/code/01-basic/L-cpp-standard/ii-cxx-standard/build/CMakeFiles/hello_cpp11.dir/DependInfo.cmake --color= 74 | Dependee "/data/code/01-basic/L-cpp-standard/ii-cxx-standard/build/CMakeFiles/hello_cpp11.dir/DependInfo.cmake" is newer than depender "/data/code/01-basic/L-cpp-standard/ii-cxx-standard/build/CMakeFiles/hello_cpp11.dir/depend.internal". 75 | Dependee "/data/code/01-basic/L-cpp-standard/ii-cxx-standard/build/CMakeFiles/CMakeDirectoryInformation.cmake" is newer than depender "/data/code/01-basic/L-cpp-standard/ii-cxx-standard/build/CMakeFiles/hello_cpp11.dir/depend.internal". 76 | Scanning dependencies of target hello_cpp11 77 | make[2]: Leaving directory '/data/code/01-basic/L-cpp-standard/ii-cxx-standard/build' 78 | make -f CMakeFiles/hello_cpp11.dir/build.make CMakeFiles/hello_cpp11.dir/build 79 | make[2]: Entering directory '/data/code/01-basic/L-cpp-standard/ii-cxx-standard/build' 80 | [ 50%] Building CXX object CMakeFiles/hello_cpp11.dir/main.cpp.o 81 | /usr/bin/c++ -std=gnu++11 -o CMakeFiles/hello_cpp11.dir/main.cpp.o -c /data/code/01-basic/L-cpp-standard/ii-cxx-standard/main.cpp 82 | [100%] Linking CXX executable hello_cpp11 83 | /usr/bin/cmake -E cmake_link_script CMakeFiles/hello_cpp11.dir/link.txt --verbose=1 84 | /usr/bin/c++ CMakeFiles/hello_cpp11.dir/main.cpp.o -o hello_cpp11 -rdynamic 85 | make[2]: Leaving directory '/data/code/01-basic/L-cpp-standard/ii-cxx-standard/build' 86 | [100%] Built target hello_cpp11 87 | make[1]: Leaving directory '/data/code/01-basic/L-cpp-standard/ii-cxx-standard/build' 88 | ---- 89 | -------------------------------------------------------------------------------- /01-basic/L-cpp-standard/ii-cxx-standard/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | auto message = "Hello C++11"; 6 | std::cout << message << std::endl; 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /01-basic/L-cpp-standard/iii-compile-features/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Set the minimum version of CMake that can be used 2 | # To find the cmake version run 3 | # $ cmake --version 4 | cmake_minimum_required(VERSION 3.1) 5 | 6 | # Set the project name 7 | project (hello_cpp11) 8 | 9 | # Add an executable 10 | add_executable(hello_cpp11 main.cpp) 11 | 12 | # set the C++ standard to the appropriate standard for using auto 13 | target_compile_features(hello_cpp11 PUBLIC cxx_auto_type) 14 | 15 | # Print the list of known compile features for this version of CMake 16 | message("List of compile features: ${CMAKE_CXX_COMPILE_FEATURES}") 17 | -------------------------------------------------------------------------------- /01-basic/L-cpp-standard/iii-compile-features/README.adoc: -------------------------------------------------------------------------------- 1 | = Set C++ Standard 2 | :toc: 3 | :toc-placement!: 4 | 5 | toc::[] 6 | 7 | # Introduction 8 | 9 | This example shows how to set the C++ standard using the `target_compile_features` function. This is available since CMake v3.1 10 | 11 | The files in this tutorial are below: 12 | 13 | ``` 14 | A-hello-cmake$ tree 15 | . 16 | ├── CMakeLists.txt 17 | ├── main.cpp 18 | ``` 19 | 20 | * link:CMakeLists.txt[CMakeLists.txt] - Contains the CMake commands you wish to run 21 | * link:main.cpp[main.cpp] - A simple "Hello World" cpp file targeting C++11. 22 | 23 | # Concepts 24 | 25 | ## Using target_compile_features 26 | 27 | Calling the link:https://cmake.org/cmake/help/v3.1/command/target_compile_features.html[target_compile_features] function on a target will look at the passed in feature and determine the correct compiler flag to use for your target. 28 | 29 | [source,cmake] 30 | ---- 31 | target_compile_features(hello_cpp11 PUBLIC cxx_auto_type) 32 | ---- 33 | 34 | As with other `target_*` functions, you can specify the scope of the feature for the selected target. This populates the link:https://cmake.org/cmake/help/v3.1/prop_tgt/INTERFACE_COMPILE_FEATURES.html#prop_tgt:INTERFACE_COMPILE_FEATURES[INTERFACE_COMPILE_FEATURES] property for the target. 35 | 36 | The list of available features can be found from the link:https://cmake.org/cmake/help/v3.1/variable/CMAKE_CXX_COMPILE_FEATURES.html#variable:CMAKE_CXX_COMPILE_FEATURES[CMAKE_CXX_COMPILE_FEATURES] variable. You can obtain a list of the available features using the following code: 37 | 38 | [source,cmake] 39 | ---- 40 | message("List of compile features: ${CMAKE_CXX_COMPILE_FEATURES}") 41 | ---- 42 | 43 | # Building the Examples 44 | 45 | Below is sample output from building this example. 46 | 47 | [source,bash] 48 | ---- 49 | $ mkdir build 50 | $ cd build 51 | 52 | $ cmake .. 53 | -- The C compiler identification is GNU 5.4.0 54 | -- The CXX compiler identification is GNU 5.4.0 55 | -- Check for working C compiler: /usr/bin/cc 56 | -- Check for working C compiler: /usr/bin/cc -- works 57 | -- Detecting C compiler ABI info 58 | -- Detecting C compiler ABI info - done 59 | -- Detecting C compile features 60 | -- Detecting C compile features - done 61 | -- Check for working CXX compiler: /usr/bin/c++ 62 | -- Check for working CXX compiler: /usr/bin/c++ -- works 63 | -- Detecting CXX compiler ABI info 64 | -- Detecting CXX compiler ABI info - done 65 | -- Detecting CXX compile features 66 | -- Detecting CXX compile features - done 67 | List of compile features: cxx_template_template_parameters;cxx_alias_templates;cxx_alignas;cxx_alignof;cxx_attributes;cxx_auto_type;cxx_constexpr;cxx_decltype;cxx_decltype_incomplete_return_types;cxx_default_function_template_args;cxx_defaulted_functions;cxx_defaulted_move_initializers;cxx_delegating_constructors;cxx_deleted_functions;cxx_enum_forward_declarations;cxx_explicit_conversions;cxx_extended_friend_declarations;cxx_extern_templates;cxx_final;cxx_func_identifier;cxx_generalized_initializers;cxx_inheriting_constructors;cxx_inline_namespaces;cxx_lambdas;cxx_local_type_template_args;cxx_long_long_type;cxx_noexcept;cxx_nonstatic_member_init;cxx_nullptr;cxx_override;cxx_range_for;cxx_raw_string_literals;cxx_reference_qualified_functions;cxx_right_angle_brackets;cxx_rvalue_references;cxx_sizeof_member;cxx_static_assert;cxx_strong_enums;cxx_thread_local;cxx_trailing_return_types;cxx_unicode_literals;cxx_uniform_initialization;cxx_unrestricted_unions;cxx_user_literals;cxx_variadic_macros;cxx_variadic_templates;cxx_aggregate_default_initializers;cxx_attribute_deprecated;cxx_binary_literals;cxx_contextual_conversions;cxx_decltype_auto;cxx_digit_separators;cxx_generic_lambdas;cxx_lambda_init_captures;cxx_relaxed_constexpr;cxx_return_type_deduction;cxx_variable_templates 68 | -- Configuring done 69 | -- Generating done 70 | -- Build files have been written to: /data/code/01-basic/L-cpp-standard/iii-compile-features/build 71 | 72 | 73 | $ make VERBOSE=1 74 | /usr/bin/cmake -H/data/code/01-basic/L-cpp-standard/iii-compile-features -B/data/code/01-basic/L-cpp-standard/iii-compile-features/build --check-build-system CMakeFiles/Makefile.cmake 0 75 | /usr/bin/cmake -E cmake_progress_start /data/code/01-basic/L-cpp-standard/iii-compile-features/build/CMakeFiles /data/code/01-basic/L-cpp-standard/iii-compile-features/build/CMakeFiles/progress.marks 76 | make -f CMakeFiles/Makefile2 all 77 | make[1]: Entering directory '/data/code/01-basic/L-cpp-standard/iii-compile-features/build' 78 | make -f CMakeFiles/hello_cpp11.dir/build.make CMakeFiles/hello_cpp11.dir/depend 79 | make[2]: Entering directory '/data/code/01-basic/L-cpp-standard/iii-compile-features/build' 80 | cd /data/code/01-basic/L-cpp-standard/iii-compile-features/build && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /data/code/01-basic/L-cpp-standard/iii-compile-features /data/code/01-basic/L-cpp-standard/iii-compile-features /data/code/01-basic/L-cpp-standard/iii-compile-features/build /data/code/01-basic/L-cpp-standard/iii-compile-features/build /data/code/01-basic/L-cpp-standard/iii-compile-features/build/CMakeFiles/hello_cpp11.dir/DependInfo.cmake --color= 81 | Dependee "/data/code/01-basic/L-cpp-standard/iii-compile-features/build/CMakeFiles/hello_cpp11.dir/DependInfo.cmake" is newer than depender "/data/code/01-basic/L-cpp-standard/iii-compile-features/build/CMakeFiles/hello_cpp11.dir/depend.internal". 82 | Dependee "/data/code/01-basic/L-cpp-standard/iii-compile-features/build/CMakeFiles/CMakeDirectoryInformation.cmake" is newer than depender "/data/code/01-basic/L-cpp-standard/iii-compile-features/build/CMakeFiles/hello_cpp11.dir/depend.internal". 83 | Scanning dependencies of target hello_cpp11 84 | make[2]: Leaving directory '/data/code/01-basic/L-cpp-standard/iii-compile-features/build' 85 | make -f CMakeFiles/hello_cpp11.dir/build.make CMakeFiles/hello_cpp11.dir/build 86 | make[2]: Entering directory '/data/code/01-basic/L-cpp-standard/iii-compile-features/build' 87 | [ 50%] Building CXX object CMakeFiles/hello_cpp11.dir/main.cpp.o 88 | /usr/bin/c++ -std=gnu++11 -o CMakeFiles/hello_cpp11.dir/main.cpp.o -c /data/code/01-basic/L-cpp-standard/iii-compile-features/main.cpp 89 | [100%] Linking CXX executable hello_cpp11 90 | /usr/bin/cmake -E cmake_link_script CMakeFiles/hello_cpp11.dir/link.txt --verbose=1 91 | /usr/bin/c++ CMakeFiles/hello_cpp11.dir/main.cpp.o -o hello_cpp11 -rdynamic 92 | make[2]: Leaving directory '/data/code/01-basic/L-cpp-standard/iii-compile-features/build' 93 | [100%] Built target hello_cpp11 94 | make[1]: Leaving directory '/data/code/01-basic/L-cpp-standard/iii-compile-features/build' 95 | /usr/bin/cmake -E cmake_progress_start /data/code/01-basic/L-cpp-standard/iii-compile-features/build/CMakeFiles 0 96 | 97 | ---- 98 | -------------------------------------------------------------------------------- /01-basic/L-cpp-standard/iii-compile-features/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | auto message = "Hello C++11"; 6 | std::cout << message << std::endl; 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /01-basic/README.adoc: -------------------------------------------------------------------------------- 1 | = Basic Examples 2 | 3 | The basic examples in this directory show how the setup a CMake project, 4 | set compile flags, create and link executables and libraries, and install them. 5 | 6 | The examples included are 7 | 8 | - link:A-hello-cmake[hello-cmake]. A hello world example. 9 | - link:B-hello-headers[hello-headers]. A slightly more complicated hello world example, using separate source and include folders. 10 | - link:C-static-library[static-library]. An example using a static library. 11 | - link:D-shared-library[shared-library]. An example using a shared library. 12 | - link:E-installing[installing]. Shows how to create a 'make install' target that will install binaries and libraries. 13 | - link:F-build-type[build-type]. An example showing how to set a default build and optimization flags for your project. 14 | - link:G-compile-flags[compile-flags]. Shows how to set additional compile flags. 15 | - link:H-third-party-library[third-party-library]. Shows an example of how to link third party libraries. 16 | - link:I-compiling-with-clang[compiling-with-clang]. An example of invoking the clang compiler. 17 | - link:J-building-with-ninja[building-with-ninja] - Shows how to generate ninja build files 18 | - link:K-imported-targets[imported-targets] - Shows how to link boost using the new imported targets 19 | - link:L-cpp-standard[cpp-standard] - Shows various methods to set the C++ standard 20 | -------------------------------------------------------------------------------- /02-sub-projects/A-basic/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.5) 2 | 3 | project(subprojects) 4 | 5 | # Add sub directories 6 | add_subdirectory(sublibrary1) 7 | add_subdirectory(sublibrary2) 8 | add_subdirectory(subbinary) 9 | -------------------------------------------------------------------------------- /02-sub-projects/A-basic/subbinary/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(subbinary) 2 | 3 | # Create the executable 4 | add_executable(${PROJECT_NAME} main.cpp) 5 | 6 | # Link the static library from subproject1 using its alias sub::lib1 7 | # Link the header only library from subproject2 using its alias sub::lib2 8 | # This will cause the include directories for that target to be added to this project 9 | target_link_libraries(${PROJECT_NAME} 10 | sub::lib1 11 | sub::lib2 12 | ) 13 | -------------------------------------------------------------------------------- /02-sub-projects/A-basic/subbinary/main.cpp: -------------------------------------------------------------------------------- 1 | #include "sublib1/sublib1.h" 2 | #include "sublib2/sublib2.h" 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | sublib1 hi; 7 | hi.print(); 8 | 9 | sublib2 howdy; 10 | howdy.print(); 11 | 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /02-sub-projects/A-basic/sublibrary1/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Set the project name 2 | project (sublibrary1) 3 | 4 | # Add a library with the above sources 5 | add_library(${PROJECT_NAME} src/sublib1.cpp) 6 | add_library(sub::lib1 ALIAS ${PROJECT_NAME}) 7 | 8 | target_include_directories( ${PROJECT_NAME} 9 | PUBLIC ${PROJECT_SOURCE_DIR}/include 10 | ) 11 | -------------------------------------------------------------------------------- /02-sub-projects/A-basic/sublibrary1/include/sublib1/sublib1.h: -------------------------------------------------------------------------------- 1 | #ifndef __SUBLIB_1_H__ 2 | #define __SUBLIB_1_H__ 3 | 4 | class sublib1 5 | { 6 | public: 7 | void print(); 8 | }; 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /02-sub-projects/A-basic/sublibrary1/src/sublib1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "sublib1/sublib1.h" 4 | 5 | void sublib1::print() 6 | { 7 | std::cout << "Hello sub-library 1!" << std::endl; 8 | } 9 | -------------------------------------------------------------------------------- /02-sub-projects/A-basic/sublibrary2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Set the project name 2 | project (sublibrary2) 3 | 4 | add_library(${PROJECT_NAME} INTERFACE) 5 | add_library(sub::lib2 ALIAS ${PROJECT_NAME}) 6 | 7 | target_include_directories(${PROJECT_NAME} 8 | INTERFACE 9 | ${PROJECT_SOURCE_DIR}/include 10 | ) 11 | -------------------------------------------------------------------------------- /02-sub-projects/A-basic/sublibrary2/include/sublib2/sublib2.h: -------------------------------------------------------------------------------- 1 | #ifndef __SUBLIB_2_H__ 2 | #define __SUBLIB_2_H__ 3 | 4 | #include 5 | 6 | class sublib2 7 | { 8 | public: 9 | void print() 10 | { 11 | std::cout << "Hello header only sub-library 2!" << std::endl; 12 | } 13 | }; 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /02-sub-projects/README.adoc: -------------------------------------------------------------------------------- 1 | = Sub-Project Examples 2 | 3 | Many large projects are made up of different libraries and binaries. These 4 | can be organised into multiple folders and sub-projects to ease development. 5 | 6 | The examples included are 7 | 8 | - link:A-basic[basic] - This basic example includes a static library, a header only library 9 | and an executable 10 | -------------------------------------------------------------------------------- /03-code-generation/README.adoc: -------------------------------------------------------------------------------- 1 | = Code Generation 2 | 3 | Code generation can be useful to create source code in different languages from a common description file. This can reduce the amount of manual code to write and increase interoperability. 4 | 5 | Examples showing code generation using variables from CMake and also using some common tools. 6 | 7 | * link:configure-files[configure-file] - Using the CMake configure_file function to inject CMake variables. 8 | * link:protobuf[Protocol Buffers] - Using Google Protocol Buffers to generate C++ source. 9 | -------------------------------------------------------------------------------- /03-code-generation/configure-files/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | # Set the project name 4 | project (cf_example) 5 | 6 | # set a project version 7 | set (cf_example_VERSION_MAJOR 0) 8 | set (cf_example_VERSION_MINOR 2) 9 | set (cf_example_VERSION_PATCH 1) 10 | set (cf_example_VERSION "${cf_example_VERSION_MAJOR}.${cf_example_VERSION_MINOR}.${cf_example_VERSION_PATCH}") 11 | 12 | # Call configure files on ver.h.in to set the version. 13 | # Uses the standard ${VARIABLE} syntax in the file 14 | configure_file(ver.h.in ${PROJECT_BINARY_DIR}/ver.h) 15 | 16 | # configure the path.h.in file. 17 | # This file can only use the @VARIABLE@ syntax in the file 18 | configure_file(path.h.in ${PROJECT_BINARY_DIR}/path.h @ONLY) 19 | 20 | # Add an executable 21 | add_executable(cf_example 22 | main.cpp 23 | ) 24 | 25 | # include the directory with the new files 26 | target_include_directories( cf_example 27 | PUBLIC 28 | ${CMAKE_BINARY_DIR} 29 | ) 30 | -------------------------------------------------------------------------------- /03-code-generation/configure-files/README.adoc: -------------------------------------------------------------------------------- 1 | = Configure Files Generation 2 | :toc: 3 | :toc-placement!: 4 | 5 | toc::[] 6 | 7 | # Introduction 8 | 9 | During the call to cmake it is possible to create files that use variables from 10 | the CMakeLists.txt and cmake cache. During CMake generation the file is copied to a 11 | new location and any cmake variables are replaced. 12 | 13 | The files in this tutorial are below: 14 | 15 | ``` 16 | $ tree 17 | . 18 | ├── CMakeLists.txt 19 | ├── main.cpp 20 | ├── path.h.in 21 | ├── ver.h.in 22 | ``` 23 | 24 | * link:CMakeLists.txt[] - Contains the CMake commands you wish to run 25 | * link:main.cpp[] - The source file with main 26 | * link:path.h.in[] - File to contain a path to the build directory 27 | * link:ver.h.in[] - File to contain the version of the project 28 | 29 | # Concepts 30 | 31 | ## Configure Files 32 | 33 | To do variable substitution in a file you can use the `configure_file()` function 34 | in CMake. This core arguments for this function are source file and destination file. 35 | 36 | [source,cmake] 37 | ---- 38 | configure_file(ver.h.in ${PROJECT_BINARY_DIR}/ver.h) 39 | 40 | configure_file(path.h.in ${PROJECT_BINARY_DIR}/path.h @ONLY) 41 | ---- 42 | 43 | The first example above, allows the variable to be defined like a CMake variables using 44 | the `${}` syntax or an `@@` in the ver.h.in file. After generation a new file ver.h will be available 45 | in the `PROJECT_BINARY_DIR`. 46 | 47 | ``` 48 | const char* ver = "${cf_example_VERSION}"; 49 | ``` 50 | 51 | The second example, only allows variables to be defined using the `@@` syntax in the path.h.in file. 52 | After generation a new file path.h will be available in the `PROJECT_BINARY_DIR`. 53 | 54 | ``` 55 | const char* path = "@CMAKE_SOURCE_DIR@"; 56 | ``` 57 | 58 | # Building the Example 59 | 60 | [source,bash] 61 | ---- 62 | $ mkdir build 63 | 64 | $ cd build/ 65 | 66 | $ cmake .. 67 | -- The C compiler identification is GNU 4.8.4 68 | -- The CXX compiler identification is GNU 4.8.4 69 | -- Check for working C compiler: /usr/bin/cc 70 | -- Check for working C compiler: /usr/bin/cc -- works 71 | -- Detecting C compiler ABI info 72 | -- Detecting C compiler ABI info - done 73 | -- Check for working CXX compiler: /usr/bin/c++ 74 | -- Check for working CXX compiler: /usr/bin/c++ -- works 75 | -- Detecting CXX compiler ABI info 76 | -- Detecting CXX compiler ABI info - done 77 | -- Configuring done 78 | -- Generating done 79 | -- Build files have been written to: /home/matrim/workspace/cmake-examples/03-code-generation/configure-files/build 80 | 81 | $ ls 82 | CMakeCache.txt CMakeFiles cmake_install.cmake Makefile path.h ver.h 83 | 84 | $ cat path.h 85 | #ifndef __PATH_H__ 86 | #define __PATH_H__ 87 | 88 | // version variable that will be substituted by cmake 89 | // This shows an example using the @ variable type 90 | const char* path = "/home/matrim/workspace/cmake-examples/03-code-generation/configure-files"; 91 | 92 | #endif 93 | 94 | $ cat ver.h 95 | #ifndef __VER_H__ 96 | #define __VER_H__ 97 | 98 | // version variable that will be substituted by cmake 99 | // This shows an example using the $ variable type 100 | const char* ver = "0.2.1"; 101 | 102 | #endif 103 | 104 | $ make 105 | Scanning dependencies of target cf_example 106 | [100%] Building CXX object CMakeFiles/cf_example.dir/main.cpp.o 107 | Linking CXX executable cf_example 108 | [100%] Built target cf_example 109 | 110 | $ ./cf_example 111 | Hello Version 0.2.1! 112 | Path is /home/matrim/workspace/cmake-examples/03-code-generation/configure-files 113 | ---- 114 | -------------------------------------------------------------------------------- /03-code-generation/configure-files/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "ver.h" 3 | #include "path.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | std::cout << "Hello Version " << ver << "!" << std::endl; 8 | std::cout << "Path is " << path << std::endl; 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /03-code-generation/configure-files/path.h.in: -------------------------------------------------------------------------------- 1 | #ifndef __PATH_H__ 2 | #define __PATH_H__ 3 | 4 | // version variable that will be substituted by cmake 5 | // This shows an example using the @ variable type 6 | const char* path = "@CMAKE_SOURCE_DIR@"; 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /03-code-generation/configure-files/ver.h.in: -------------------------------------------------------------------------------- 1 | #ifndef __VER_H__ 2 | #define __VER_H__ 3 | 4 | // version variable that will be substituted by cmake 5 | // This shows an example using the $ variable type 6 | const char* ver = "${cf_example_VERSION}"; 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /03-code-generation/protobuf/AddressBook.proto: -------------------------------------------------------------------------------- 1 | package tutorial; 2 | 3 | message Person { 4 | required string name = 1; 5 | required int32 id = 2; 6 | optional string email = 3; 7 | 8 | enum PhoneType { 9 | MOBILE = 0; 10 | HOME = 1; 11 | WORK = 2; 12 | } 13 | 14 | message PhoneNumber { 15 | required string number = 1; 16 | optional PhoneType type = 2 [default = HOME]; 17 | } 18 | 19 | repeated PhoneNumber phone = 4; 20 | } 21 | 22 | message AddressBook { 23 | repeated Person person = 1; 24 | } 25 | -------------------------------------------------------------------------------- /03-code-generation/protobuf/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | # Set the project name 4 | project (protobuf_example) 5 | 6 | # find the protobuf compiler and libraries 7 | find_package(Protobuf REQUIRED) 8 | 9 | # check if protobuf was found 10 | if(PROTOBUF_FOUND) 11 | message ("protobuf found") 12 | else() 13 | message (FATAL_ERROR "Cannot find Protobuf") 14 | endif() 15 | 16 | # Generate the .h and .cxx files 17 | PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS AddressBook.proto) 18 | 19 | # Print path to generated files 20 | message ("PROTO_SRCS = ${PROTO_SRCS}") 21 | message ("PROTO_HDRS = ${PROTO_HDRS}") 22 | 23 | # Add an executable 24 | add_executable(protobuf_example 25 | main.cpp 26 | ${PROTO_SRCS} 27 | ${PROTO_HDRS}) 28 | 29 | target_include_directories(protobuf_example 30 | PUBLIC 31 | ${PROTOBUF_INCLUDE_DIRS} 32 | ${CMAKE_CURRENT_BINARY_DIR} 33 | ) 34 | 35 | # link the exe against the libraries 36 | target_link_libraries(protobuf_example 37 | PUBLIC 38 | ${PROTOBUF_LIBRARIES} 39 | ) 40 | -------------------------------------------------------------------------------- /03-code-generation/protobuf/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "AddressBook.pb.h" 5 | using namespace std; 6 | 7 | // This function fills in a Person message based on user input. 8 | void PromptForAddress(tutorial::Person* person) { 9 | cout << "Enter person ID number: "; 10 | int id; 11 | cin >> id; 12 | person->set_id(id); 13 | cin.ignore(256, '\n'); 14 | 15 | cout << "Enter name: "; 16 | getline(cin, *person->mutable_name()); 17 | 18 | cout << "Enter email address (blank for none): "; 19 | string email; 20 | getline(cin, email); 21 | if (!email.empty()) { 22 | person->set_email(email); 23 | } 24 | 25 | while (true) { 26 | cout << "Enter a phone number (or leave blank to finish): "; 27 | string number; 28 | getline(cin, number); 29 | if (number.empty()) { 30 | break; 31 | } 32 | 33 | tutorial::Person::PhoneNumber* phone_number = person->add_phone(); 34 | phone_number->set_number(number); 35 | 36 | cout << "Is this a mobile, home, or work phone? "; 37 | string type; 38 | getline(cin, type); 39 | if (type == "mobile") { 40 | phone_number->set_type(tutorial::Person::MOBILE); 41 | } else if (type == "home") { 42 | phone_number->set_type(tutorial::Person::HOME); 43 | } else if (type == "work") { 44 | phone_number->set_type(tutorial::Person::WORK); 45 | } else { 46 | cout << "Unknown phone type. Using default." << endl; 47 | } 48 | } 49 | } 50 | 51 | // Main function: Reads the entire address book from a file, 52 | // adds one person based on user input, then writes it back out to the same 53 | // file. 54 | int main(int argc, char* argv[]) { 55 | // Verify that the version of the library that we linked against is 56 | // compatible with the version of the headers we compiled against. 57 | GOOGLE_PROTOBUF_VERIFY_VERSION; 58 | 59 | if (argc != 2) { 60 | cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl; 61 | return -1; 62 | } 63 | 64 | tutorial::AddressBook address_book; 65 | 66 | { 67 | // Read the existing address book. 68 | fstream input(argv[1], ios::in | ios::binary); 69 | if (!input) { 70 | cout << argv[1] << ": File not found. Creating a new file." << endl; 71 | } else if (!address_book.ParseFromIstream(&input)) { 72 | cerr << "Failed to parse address book." << endl; 73 | return -1; 74 | } 75 | } 76 | 77 | // Add an address. 78 | PromptForAddress(address_book.add_person()); 79 | 80 | { 81 | // Write the new address book back to disk. 82 | fstream output(argv[1], ios::out | ios::trunc | ios::binary); 83 | if (!address_book.SerializeToOstream(&output)) { 84 | cerr << "Failed to write address book." << endl; 85 | return -1; 86 | } 87 | } 88 | 89 | // Optional: Delete all global objects allocated by libprotobuf. 90 | google::protobuf::ShutdownProtobufLibrary(); 91 | 92 | return 0; 93 | } 94 | -------------------------------------------------------------------------------- /04-static-analysis/README.adoc: -------------------------------------------------------------------------------- 1 | = Static Analysis 2 | :toc: 3 | :toc-placement!: 4 | 5 | toc::[] 6 | 7 | # Introduction 8 | 9 | Static analysis is the analysis of code without executing it. It can be 10 | used to find common programming errors and enforce coding guidelines. 11 | Examples of errors that can be found using static analysis tools 12 | include: 13 | 14 | * Out of bounds errors 15 | * Memory leaks 16 | * Usage of uninitialized variables 17 | * Use of unsafe functions 18 | 19 | Analysis tools can detect errors early and are becoming a standard tool 20 | in most build chains. Some build tools such as 21 | http://clang-analyzer.llvm.org/[Clang] include a build in static 22 | analysis tool. However standalone tools also exist. 23 | 24 | The examples here include using the following tools: 25 | 26 | * http://cppcheck.sourceforge.net/[CppCheck] 27 | * https://clang-analyzer.llvm.org/[Clang Static Analyzer] 28 | * https://clang.llvm.org/docs/ClangFormat.html[Clang Format] 29 | -------------------------------------------------------------------------------- /04-static-analysis/clang-analyzer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.5) 2 | 3 | project(cppcheck_analysis) 4 | 5 | # Use debug build as recommended 6 | set(CMAKE_BUILD_TYPE Debug) 7 | 8 | # Have cmake create a compile database 9 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 10 | 11 | # Add sub directories 12 | add_subdirectory(subproject1) 13 | add_subdirectory(subproject2) 14 | -------------------------------------------------------------------------------- /04-static-analysis/clang-analyzer/README.adoc: -------------------------------------------------------------------------------- 1 | = clang-analyzer 2 | :toc: 3 | :toc-placement!: 4 | 5 | toc::[] 6 | 7 | # Introduction 8 | 9 | This example shows how to call the 10 | https://clang-analyzer.llvm.org/[Clang Static Analyzer] to do static analysis using the 11 | scan-build tool. 12 | 13 | The files included in this example are: 14 | 15 | ``` 16 | $ tree 17 | . 18 | ├── CMakeLists.txt 19 | ├── subproject1 20 | │   ├── CMakeLists.txt 21 | │   └── main1.cpp 22 | └── subproject2 23 | ├── CMakeLists.txt 24 | └── main2.cpp 25 | ``` 26 | 27 | * link:CMakeLists.txt[] - Top level CMakeLists.txt 28 | * link:subproject1/CMakeLists.txt[] - CMake commands for subproject 1 29 | * link:subproject1/main.cpp[] - source for a subproject with no errors 30 | * link:subproject2/CMakeLists.txt[] - CMake commands for subproject 2 31 | * link:subproject2/main2.cpp[] - source for a subproject that includes errors 32 | 33 | # Requirements 34 | 35 | To run this example you must have clang analyzer and the scan-build tool installed. This can be installed on Ubuntu using the following command. 36 | 37 | [source,bash] 38 | ---- 39 | $ sudo apt-get install clang 40 | ---- 41 | 42 | It will result in the tool being available as: 43 | 44 | [source,bash] 45 | ---- 46 | $ scan-build-3.6 47 | ---- 48 | 49 | # Concepts 50 | 51 | ## scan-build 52 | 53 | To run clang static analyzer you can use the tool `scan-build` to run the analyzer when you 54 | also run the compiler. This overrides the CC and CXX environment variables and replaces them with it's own tools. To run it you can do 55 | 56 | [source,bash] 57 | ---- 58 | $ scan-build-3.6 cmake .. 59 | $ scan-build-3.6 make 60 | ---- 61 | 62 | By default this will run the standard compiler for your platform, i.e. `gcc` on linux. However, if you want to override this you can change the command to: 63 | 64 | [source,bash] 65 | ---- 66 | $ scan-build-3.6 --use-cc=clang-3.6 --use-c++=clang++-3.6 -o ./scanbuildout/ make 67 | ---- 68 | 69 | ## scan-build output 70 | 71 | scan-build will only output warnings during compile time and will also generate a list of HTML files which contain detailed analysis of the error. 72 | 73 | [source,bash] 74 | ---- 75 | $ cd scanbuildout/ 76 | $ tree 77 | . 78 | └── 2017-07-03-213514-3653-1 79 | ├── index.html 80 | ├── report-42eba1.html 81 | ├── scanview.css 82 | └── sorttable.js 83 | 84 | 1 directory, 4 files 85 | ---- 86 | 87 | By default these are output to +/tmp/scanbuildout/{run folder}+. You can change this using `scan-build -o /output/folder`. 88 | 89 | # Building the example 90 | 91 | [source,bash] 92 | ---- 93 | $ mkdir build 94 | 95 | $ cd build/ 96 | 97 | $ scan-build-3.6 -o ./scanbuildout make 98 | scan-build: Using '/usr/lib/llvm-3.6/bin/clang' for static analysis 99 | make: *** No targets specified and no makefile found. Stop. 100 | scan-build: Removing directory '/data/code/clang-analyzer/build/scanbuildout/2017-07-03-211632-937-1' because it contains no reports. 101 | scan-build: No bugs found. 102 | devuser@91457fbfa423:/data/code/clang-analyzer/build$ scan-build-3.6 -o ./scanbuildout cmake .. 103 | scan-build: Using '/usr/lib/llvm-3.6/bin/clang' for static analysis 104 | -- The C compiler identification is GNU 5.4.0 105 | -- The CXX compiler identification is GNU 5.4.0 106 | -- Check for working C compiler: /usr/share/clang/scan-build-3.6/ccc-analyzer 107 | -- Check for working C compiler: /usr/share/clang/scan-build-3.6/ccc-analyzer -- works 108 | -- Detecting C compiler ABI info 109 | -- Detecting C compiler ABI info - done 110 | -- Detecting C compile features 111 | -- Detecting C compile features - done 112 | -- Check for working CXX compiler: /usr/share/clang/scan-build-3.6/c++-analyzer 113 | -- Check for working CXX compiler: /usr/share/clang/scan-build-3.6/c++-analyzer -- works 114 | -- Detecting CXX compiler ABI info 115 | -- Detecting CXX compiler ABI info - done 116 | -- Detecting CXX compile features 117 | -- Detecting CXX compile features - done 118 | -- Found CPPCHECK: /usr/local/bin/cppcheck 119 | cppcheck found. Use cppccheck-analysis targets to run it 120 | -- Configuring done 121 | -- Generating done 122 | -- Build files have been written to: /data/code/clang-analyzer/build 123 | scan-build: Removing directory '/data/code/clang-analyzer/build/scanbuildout/2017-07-03-211641-941-1' because it contains no reports. 124 | scan-build: No bugs found. 125 | 126 | $ $ scan-build-3.6 -o ./scanbuildout make 127 | scan-build: Using '/usr/lib/llvm-3.6/bin/clang' for static analysis 128 | Scanning dependencies of target subproject1 129 | [ 25%] Building CXX object subproject1/CMakeFiles/subproject1.dir/main1.cpp.o 130 | [ 50%] Linking CXX executable subproject1 131 | [ 50%] Built target subproject1 132 | Scanning dependencies of target subproject2 133 | [ 75%] Building CXX object subproject2/CMakeFiles/subproject2.dir/main2.cpp.o 134 | /data/code/clang-analyzer/subproject2/main2.cpp:7:17: warning: Dereference of null pointer (loaded from variable 'x') 135 | std::cout << *x << std::endl; 136 | ^~ 137 | 1 warning generated. 138 | [100%] Linking CXX executable subproject2 139 | [100%] Built target subproject2 140 | scan-build: 1 bug found. 141 | scan-build: Run 'scan-view /data/code/clang-analyzer/build/scanbuildout/2017-07-03-211647-1172-1' to examine bug reports. 142 | 143 | $ cd scanbuildout/ 144 | $ tree 145 | . 146 | └── 2017-07-03-213514-3653-1 147 | ├── index.html 148 | ├── report-42eba1.html 149 | ├── scanview.css 150 | └── sorttable.js 151 | 152 | 1 directory, 4 files 153 | ---- 154 | 155 | -------------------------------------------------------------------------------- /04-static-analysis/clang-analyzer/run_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | mkdir -p build \ 3 | && cd build \ 4 | && scan-build-3.6 -o scanbuildout cmake .. \ 5 | && scan-build-3.6 -o scanbuildout make 6 | -------------------------------------------------------------------------------- /04-static-analysis/clang-analyzer/subproject1/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Set the project name 2 | project (subproject1) 3 | 4 | # Add an executable with the above sources 5 | add_executable(${PROJECT_NAME} main1.cpp) 6 | -------------------------------------------------------------------------------- /04-static-analysis/clang-analyzer/subproject1/main1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | std::cout << "Hello Main1!" << std::endl; 6 | return 0; 7 | } -------------------------------------------------------------------------------- /04-static-analysis/clang-analyzer/subproject2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Set the project name 2 | project (subproject2) 3 | 4 | # Add an executable with the above sources 5 | add_executable(${PROJECT_NAME} main2.cpp) 6 | -------------------------------------------------------------------------------- /04-static-analysis/clang-analyzer/subproject2/main2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | std::cout << "Hello Main2!" << std::endl; 6 | int* x = NULL; 7 | std::cout << *x << std::endl; 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /04-static-analysis/clang-format/.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | AccessModifierOffset: -4 5 | AlignEscapedNewlinesLeft: false 6 | AlignOperands: true 7 | AlignTrailingComments: true 8 | AllowAllParametersOfDeclarationOnNextLine: true 9 | AllowShortBlocksOnASingleLine: false 10 | AllowShortCaseLabelsOnASingleLine: false 11 | AllowShortFunctionsOnASingleLine: All 12 | AllowShortIfStatementsOnASingleLine: false 13 | AllowShortLoopsOnASingleLine: false 14 | AlwaysBreakBeforeMultilineStrings: false 15 | AlwaysBreakTemplateDeclarations: false 16 | BinPackArguments: true 17 | BinPackParameters: true 18 | BreakBeforeBinaryOperators: None 19 | BreakBeforeBraces: Allman 20 | BreakBeforeTernaryOperators: true 21 | BreakConstructorInitializersBeforeComma: false 22 | ColumnLimit: 120 23 | CommentPragmas: '' 24 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 25 | ConstructorInitializerIndentWidth: 8 26 | ContinuationIndentWidth: 4 27 | Cpp11BracedListStyle: true 28 | DerivePointerAlignment: false 29 | DisableFormat: false 30 | ExperimentalAutoDetectBinPacking: false 31 | ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] 32 | IndentCaseLabels: false 33 | IndentWidth: 4 34 | IndentWrappedFunctionNames: false 35 | KeepEmptyLinesAtTheStartOfBlocks: true 36 | MaxEmptyLinesToKeep: 3 37 | NamespaceIndentation: All 38 | ObjCBlockIndentWidth: 2 39 | ObjCSpaceAfterProperty: false 40 | ObjCSpaceBeforeProtocolList: true 41 | PenaltyBreakBeforeFirstCallParameter: 19 42 | PenaltyBreakComment: 300 43 | PenaltyBreakFirstLessLess: 120 44 | PenaltyBreakString: 1000 45 | PenaltyExcessCharacter: 1000000 46 | PenaltyReturnTypeOnItsOwnLine: 60 47 | PointerAlignment: Left 48 | SpaceAfterCStyleCast: false 49 | SpaceBeforeAssignmentOperators: true 50 | SpaceBeforeParens: ControlStatements 51 | SpaceInEmptyParentheses: false 52 | SpacesBeforeTrailingComments: 1 53 | SpacesInAngles: false 54 | SpacesInContainerLiterals: true 55 | SpacesInCStyleCastParentheses: false 56 | SpacesInParentheses: false 57 | SpacesInSquareBrackets: false 58 | Standard: Cpp11 59 | TabWidth: 4 60 | UseTab: Never 61 | ... 62 | -------------------------------------------------------------------------------- /04-static-analysis/clang-format/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.5) 2 | 3 | project(cppcheck_analysis) 4 | 5 | # Add a custom CMake Modules directory 6 | set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules 7 | ${CMAKE_MODULE_PATH}) 8 | 9 | # Add sub directories 10 | add_subdirectory(subproject1) 11 | add_subdirectory(subproject2) 12 | 13 | set(CLANG_FORMAT_BIN_NAME clang-format-3.6) 14 | set(CLANG_FORMAT_EXCLUDE_PATTERNS "build/" ${CMAKE_BINARY_DIR}) 15 | find_package(ClangFormat) 16 | -------------------------------------------------------------------------------- /04-static-analysis/clang-format/README.adoc: -------------------------------------------------------------------------------- 1 | = clang-format 2 | :toc: 3 | :toc-placement!: 4 | 5 | toc::[] 6 | 7 | # Introduction 8 | 9 | This example shows how to call the 10 | https://clang.llvm.org/docs/ClangFormat.html[Clang Format] to check if your source code 11 | matches against your code style guidelines. 12 | 13 | The files included in this example are: 14 | 15 | ``` 16 | $ tree 17 | . 18 | ├── .clang-format 19 | ├── CMakeLists.txt 20 | ├── cmake 21 | │   ├── modules 22 | │   │   ├── clang-format.cmake 23 | │   │   └── FindClangFormat.cmake 24 | │   └── scripts 25 | │   └── clang-format-check-changed 26 | ├── subproject1 27 | │   ├── CMakeLists.txt 28 | │   └── main1.cpp 29 | └── subproject2 30 | ├── CMakeLists.txt 31 | └── main2.cpp 32 | ``` 33 | 34 | * link:CMakeLists.txt[] - Top level CMakeLists.txt 35 | * link:.clang-format[] - The file describing the style guide 36 | * link:cmake/modules/FindClangFormat.cmake[] - Script to find the clang-format binary 37 | * link:cmake/modules/clang-format.cmake[] - Script to setup the format targets 38 | * link:cmake/scripts/clang-format-check-changed.py[] - A helper script to check against changed files in git 39 | * link:cmake/scripts/clang-format-check-changed.py[] - An old simplified version of the above helper script 40 | * link:subproject1/CMakeLists.txt[] - CMake commands for subproject 1 41 | * link:subproject1/main1.cpp[] - source for a subproject with no style errors 42 | * link:subproject2/CMakeLists.txt[] - CMake commands for subproject 2 43 | * link:subproject2/main2.cpp[] - source for a subproject that includes style errors 44 | 45 | # Requirements 46 | 47 | To run this example you must have clang format tool installed. This can be installed on Ubuntu using the following command. 48 | 49 | [source,bash] 50 | ---- 51 | $ sudo apt-get install clang-format-3.6 52 | ---- 53 | 54 | It will result in the tool being available as: 55 | 56 | [source,bash] 57 | ---- 58 | $ clang-format-3.6 59 | ---- 60 | 61 | If you install a different version, you can edit the `CLANG_FORMAT_BIN_NAME` variable in the root CMakeLists.txt 62 | 63 | # Concepts 64 | 65 | ## clang-format 66 | 67 | +clang-format+ can scan a source file then find and optionally format it to match your 68 | companys style guidelines. There are default styles build in but you can also setup a style guide using a custom file called +.clang-format+, for example a snipped from this 69 | repositories +.clang-format+ is below: 70 | 71 | [source] 72 | ---- 73 | Language: Cpp 74 | # BasedOnStyle: LLVM 75 | AccessModifierOffset: -4 76 | AlignAfterOpenBracket: Align 77 | AlignConsecutiveAssignments: false 78 | AlignConsecutiveDeclarations: false 79 | ---- 80 | 81 | ## format style 82 | 83 | As mentioned, the style in this example is based on the +.clang-format+ file. This can be changed by editing link:cmake/modules/clang-format.cmake[clang-format.cmake] and changing 84 | the `-style=file` to the required style; 85 | 86 | # Targets 87 | 88 | This example will setup 3 targets: 89 | 90 | * format 91 | * format-check 92 | * format-check-changed 93 | 94 | ## format 95 | 96 | The format target will find any C++ source files and in place modify them to match the 97 | +.clang-format+ style. The source files are found using the following cmake code 98 | 99 | [source,cmake] 100 | ---- 101 | file(GLOB_RECURSE ALL_SOURCE_FILES *.cpp *.h *.cxx *.hxx *.hpp *.cc *.ipp) 102 | 103 | # Don't include some common build folders 104 | set(CLANG_FORMAT_EXCLUDE_PATTERNS ${CLANG_FORMAT_EXCLUDE_PATTERNS} "/CMakeFiles/" "cmake") 105 | 106 | # get all project files file 107 | foreach (SOURCE_FILE ${ALL_SOURCE_FILES}) 108 | foreach (EXCLUDE_PATTERN ${CLANG_FORMAT_EXCLUDE_PATTERNS}) 109 | string(FIND ${SOURCE_FILE} ${EXCLUDE_PATTERN} EXCLUDE_FOUND) 110 | if (NOT ${EXCLUDE_FOUND} EQUAL -1) 111 | list(REMOVE_ITEM ALL_SOURCE_FILES ${SOURCE_FILE}) 112 | endif () 113 | endforeach () 114 | endforeach () 115 | ---- 116 | 117 | This will find files matching the common C++ suffixes and then remove any that match some 118 | common CMake directories. 119 | 120 | In the root `CMakeList.txt` we also exclude the build directory by adding the line 121 | 122 | [source,cmake] 123 | ---- 124 | set(CLANG_FORMAT_EXCLUDE_PATTERNS "build/") 125 | ---- 126 | 127 | ## format-check 128 | 129 | This target will work as above but instead of formatting the files it will cause a failure 130 | if any files don't match the clang-format style 131 | 132 | ## format-check-changed 133 | 134 | This target will check the output of `git status` and scan the files to check if they match the style. This can be used by developers to make sure their changed files match the correct style. 135 | 136 | In this example the actual check is done with a helper script +clang-format-check-changed.py+. This script will run `git status --porcelain --ignore-submodules` 137 | to get a list of changed files, match them against the allowed extensions from the above list, and finally remove any 138 | that match the exclude pattern from +CLANG_FORMAT_EXCLUDE_PATTERNS+. It will then run these files through clang-format and 139 | exit with an error if the files do not match the style. 140 | 141 | An example call to the +clang-format-check-changed.py+ script is: 142 | 143 | [source,bash] 144 | ---- 145 | cmake/scripts/clang-format-check-changed.py --file-extensions ".cpp,*.cpp,*.h,*.cxx,*.hxx,*.hpp,*.cc,*.ipp" --exclude=build/ --exclude=/CMakeFiles/ --exclude=cmake --clang-format-bin /usr/bin/clang-format-3.6 146 | ---- 147 | 148 | [NOTE] 149 | ==== 150 | This will include all changed files in your git repository that match the patterns. In this example repository this can include files that 151 | are part of different examples. 152 | ==== 153 | -------------------------------------------------------------------------------- /04-static-analysis/clang-format/cmake/modules/FindClangFormat.cmake: -------------------------------------------------------------------------------- 1 | # Find Clang format 2 | # 3 | # 4 | if(NOT CLANG_FORMAT_BIN_NAME) 5 | set(CLANG_FORMAT_BIN_NAME clang-format) 6 | endif() 7 | 8 | # if custom path check there first 9 | if(CLANG_FORMAT_ROOT_DIR) 10 | find_program(CLANG_FORMAT_BIN 11 | NAMES 12 | ${CLANG_FORMAT_BIN_NAME} 13 | PATHS 14 | "${CLANG_FORMAT_ROOT_DIR}" 15 | NO_DEFAULT_PATH) 16 | endif() 17 | 18 | find_program(CLANG_FORMAT_BIN NAMES ${CLANG_FORMAT_BIN_NAME}) 19 | 20 | include(FindPackageHandleStandardArgs) 21 | FIND_PACKAGE_HANDLE_STANDARD_ARGS( 22 | CLANG_FORMAT 23 | DEFAULT_MSG 24 | CLANG_FORMAT_BIN) 25 | 26 | mark_as_advanced( 27 | CLANG_FORMAT_BIN) 28 | 29 | if(CLANG_FORMAT_FOUND) 30 | # A CMake script to find all source files and setup clang-format targets for them 31 | include(clang-format) 32 | else() 33 | message("clang-format not found. Not setting up format targets") 34 | endif() 35 | -------------------------------------------------------------------------------- /04-static-analysis/clang-format/cmake/modules/clang-format.cmake: -------------------------------------------------------------------------------- 1 | # A CMake script to find all source files and setup clang-format targets for them 2 | 3 | # Find all source files 4 | set(CLANG_FORMAT_CXX_FILE_EXTENSIONS ${CLANG_FORMAT_CXX_FILE_EXTENSIONS} *.cpp *.h *.cxx *.hxx *.hpp *.cc *.ipp) 5 | file(GLOB_RECURSE ALL_SOURCE_FILES ${CLANG_FORMAT_CXX_FILE_EXTENSIONS}) 6 | 7 | # Don't include some common build folders 8 | set(CLANG_FORMAT_EXCLUDE_PATTERNS ${CLANG_FORMAT_EXCLUDE_PATTERNS} "/CMakeFiles/" "cmake") 9 | 10 | # get all project files file 11 | foreach (SOURCE_FILE ${ALL_SOURCE_FILES}) 12 | foreach (EXCLUDE_PATTERN ${CLANG_FORMAT_EXCLUDE_PATTERNS}) 13 | string(FIND ${SOURCE_FILE} ${EXCLUDE_PATTERN} EXCLUDE_FOUND) 14 | if (NOT ${EXCLUDE_FOUND} EQUAL -1) 15 | list(REMOVE_ITEM ALL_SOURCE_FILES ${SOURCE_FILE}) 16 | endif () 17 | endforeach () 18 | endforeach () 19 | 20 | add_custom_target(format 21 | COMMENT "Running clang-format to change files" 22 | COMMAND ${CLANG_FORMAT_BIN} 23 | -style=file 24 | -i 25 | ${ALL_SOURCE_FILES} 26 | ) 27 | 28 | 29 | add_custom_target(format-check 30 | COMMENT "Checking clang-format changes" 31 | # Use ! to negate the result for correct output 32 | COMMAND ! 33 | ${CLANG_FORMAT_BIN} 34 | -style=file 35 | -output-replacements-xml 36 | ${ALL_SOURCE_FILES} 37 | | grep -q "replacement offset" 38 | ) 39 | 40 | # Get the path to this file 41 | get_filename_component(_clangcheckpath ${CMAKE_CURRENT_LIST_FILE} PATH) 42 | # have at least one here by default 43 | set(CHANGED_FILE_EXTENSIONS ".cpp") 44 | foreach(EXTENSION ${CLANG_FORMAT_CXX_FILE_EXTENSIONS}) 45 | set(CHANGED_FILE_EXTENSIONS "${CHANGED_FILE_EXTENSIONS},${EXTENSION}" ) 46 | endforeach() 47 | 48 | set(EXCLUDE_PATTERN_ARGS) 49 | foreach(EXCLUDE_PATTERN ${CLANG_FORMAT_EXCLUDE_PATTERNS}) 50 | list(APPEND EXCLUDE_PATTERN_ARGS "--exclude=${EXCLUDE_PATTERN}") 51 | endforeach() 52 | 53 | # call the script to check changed files in git 54 | add_custom_target(format-check-changed 55 | COMMENT "Checking changed files in git" 56 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 57 | COMMAND ${_clangcheckpath}/../scripts/clang-format-check-changed.py 58 | --file-extensions \"${CHANGED_FILE_EXTENSIONS}\" 59 | ${EXCLUDE_PATTERN_ARGS} 60 | --clang-format-bin ${CLANG_FORMAT_BIN} 61 | ) 62 | 63 | -------------------------------------------------------------------------------- /04-static-analysis/clang-format/cmake/scripts/clang-format-check-changed: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Required because cmake root isn't git root in this example 4 | CLANG_FORMAT_BIN=$1 5 | GIT_ROOT=`git rev-parse --show-toplevel` 6 | 7 | pushd ${GIT_ROOT} > /dev/null 8 | 9 | git status --porcelain \ 10 | | egrep '*\.cpp|*\.h|*\.cxx|*\.hxx|*\.hpp|*\.cc' \ 11 | | awk -F " " '{print $NF}' \ 12 | | xargs -r ${CLANG_FORMAT_BIN} -style=file -output-replacements-xml \ 13 | | grep "replacement offset" 2>&1 > /dev/null 14 | 15 | RET=$? 16 | popd > /dev/null 17 | 18 | exit ${RET} 19 | -------------------------------------------------------------------------------- /04-static-analysis/clang-format/cmake/scripts/clang-format-check-changed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import argparse 4 | import os 5 | import sys 6 | import subprocess 7 | 8 | 9 | def check_file(filename, excludes, extensions): 10 | """ 11 | Check if a file should be included in our check 12 | """ 13 | name, ext = os.path.splitext(filename) 14 | 15 | if len(ext) > 0 and ext in extensions: 16 | if len(excludes) == 0: 17 | return True 18 | 19 | for exclude in excludes: 20 | if exclude in filename: 21 | return False 22 | 23 | return True 24 | 25 | return False 26 | 27 | 28 | def check_directory(directory, excludes, extensions): 29 | output = [] 30 | 31 | if len(excludes) > 0: 32 | for exclude in excludes: 33 | if exclude in directory: 34 | directory_excluded = False 35 | return output 36 | 37 | for root, _, files in os.walk(directory): 38 | for file in files: 39 | filename = os.path.join(root, file) 40 | if check_file(filename, excludes, extensions): 41 | print("Will check file [{}]".format(filename)) 42 | output.append(filename) 43 | return output 44 | 45 | def get_git_root(git_bin): 46 | cmd = [git_bin, "rev-parse", "--show-toplevel"] 47 | try: 48 | return subprocess.check_output(cmd).strip() 49 | except subprocess.CalledProcessError, e: 50 | print("Error calling git [{}]".format(e)) 51 | raise 52 | 53 | def clean_git_filename(line): 54 | """ 55 | Takes a line from git status --porcelain and returns the filename 56 | """ 57 | file = None 58 | git_status = line[:2] 59 | # Not an exhaustive list of git status output but should 60 | # be enough for this case 61 | # check if this is a delete 62 | if 'D' in git_status: 63 | return None 64 | # ignored file 65 | if '!' in git_status: 66 | return None 67 | # Covers renamed files 68 | if '->' in line: 69 | file = line[3:].split('->')[-1].strip() 70 | else: 71 | file = line[3:].strip() 72 | 73 | return file 74 | 75 | 76 | def get_changed_files(git_bin, excludes, file_extensions): 77 | """ 78 | Run git status and return the list of changed files 79 | """ 80 | extensions = file_extensions.split(",") 81 | # arguments coming from cmake will be *.xx. We want to remove the * 82 | for i, extension in enumerate(extensions): 83 | if extension[0] == '*': 84 | extensions[i] = extension[1:] 85 | 86 | git_root = get_git_root(git_bin) 87 | 88 | cmd = [git_bin, "status", "--porcelain", "--ignore-submodules"] 89 | print("git cmd = {}".format(cmd)) 90 | output = [] 91 | returncode = 0 92 | try: 93 | cmd_output = subprocess.check_output(cmd) 94 | for line in cmd_output.split('\n'): 95 | if len(line) > 0: 96 | file = clean_git_filename(line) 97 | if not file: 98 | continue 99 | file = os.path.join(git_root, file) 100 | 101 | if file[-1] == "/": 102 | directory_files = check_directory( 103 | file, excludes, file_extensions) 104 | output = output + directory_files 105 | else: 106 | if check_file(file, excludes, file_extensions): 107 | print("Will check file [{}]".format(file)) 108 | output.append(file) 109 | 110 | except subprocess.CalledProcessError, e: 111 | print("Error calling git [{}]".format(e)) 112 | returncode = e.returncode 113 | 114 | return output, returncode 115 | 116 | 117 | def run_clang_format(clang_format_bin, changed_files): 118 | """ 119 | Run clang format on a list of files 120 | @return 0 if formatted correctly. 121 | """ 122 | if len(changed_files) == 0: 123 | return 0 124 | cmd = [clang_format_bin, "-style=file", 125 | "-output-replacements-xml"] + changed_files 126 | print("clang-format cmd = {}".format(cmd)) 127 | try: 128 | cmd_output = subprocess.check_output(cmd) 129 | if "replacement offset" in cmd_output: 130 | print("ERROR: Changed files don't match format") 131 | return 1 132 | except subprocess.CalledProcessError, e: 133 | print("Error calling clang-format [{}]".format(e)) 134 | return e.returncode 135 | 136 | return 0 137 | 138 | 139 | def cli(): 140 | # global params 141 | parser = argparse.ArgumentParser(prog='clang-format-check-changed', 142 | description='Checks if files chagned in git match the .clang-format specification') 143 | parser.add_argument("--file-extensions", type=str, 144 | default=".cpp,.h,.cxx,.hxx,.hpp,.cc,.ipp", 145 | help="Comma separated list of file extensions to check") 146 | parser.add_argument('--exclude', action='append', default=[], 147 | help='Will not match the files / directories with these in the name') 148 | parser.add_argument('--clang-format-bin', type=str, default="clang-format", 149 | help="The clang format binary") 150 | parser.add_argument('--git-bin', type=str, default="git", 151 | help="The git binary") 152 | args = parser.parse_args() 153 | 154 | # Run gcovr to get the .gcda files form .gcno 155 | changed_files, returncode = get_changed_files( 156 | args.git_bin, args.exclude, args.file_extensions) 157 | if returncode != 0: 158 | return returncode 159 | 160 | return run_clang_format(args.clang_format_bin, changed_files) 161 | 162 | if __name__ == '__main__': 163 | sys.exit(cli()) 164 | -------------------------------------------------------------------------------- /04-static-analysis/clang-format/run_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | mkdir -p build && cd build && cmake .. && make format-check 3 | RET=$? 4 | echo "return code was ${RET}" 5 | if [ ${RET} == "0" ]; then 6 | echo "test failed. Expected format-check to fail" 7 | exit 1 8 | else 9 | echo "test success" 10 | exit 0 11 | fi 12 | -------------------------------------------------------------------------------- /04-static-analysis/clang-format/subproject1/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Set the project name 2 | project (subproject1) 3 | 4 | # Add an executable with the above sources 5 | add_executable(${PROJECT_NAME} main1.cpp) 6 | -------------------------------------------------------------------------------- /04-static-analysis/clang-format/subproject1/main1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char* argv[]) 4 | { 5 | std::cout << "Hello Main1!" << std::endl; 6 | return 0; 7 | } -------------------------------------------------------------------------------- /04-static-analysis/clang-format/subproject2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Set the project name 2 | project (subproject2) 3 | 4 | # Add an executable with the above sources 5 | add_executable(${PROJECT_NAME} main2.cpp) 6 | -------------------------------------------------------------------------------- /04-static-analysis/clang-format/subproject2/main2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class TestClass { 4 | public: 5 | TestClass(); 6 | }; 7 | 8 | TestClass::TestClass() { 9 | 10 | } 11 | 12 | int main(int argc, char* argv[]) 13 | { 14 | std::cout << "Hello Main2!" << std::endl; 15 | int* x = NULL; 16 | std::cout << *x << std::endl; 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /04-static-analysis/cppcheck-compile-commands/.cppcheck_suppressions: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttroy50/cmake-examples/2b27fc75c40447c8cf9b371cc21224dd96d6ce45/04-static-analysis/cppcheck-compile-commands/.cppcheck_suppressions -------------------------------------------------------------------------------- /04-static-analysis/cppcheck-compile-commands/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.5) 2 | 3 | project(cppcheck_analysis) 4 | 5 | # Have cmake create a compile database 6 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 7 | 8 | # Add a custom CMake Modules directory 9 | set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules 10 | ${CMAKE_MODULE_PATH}) 11 | 12 | # find the cppcheck binary 13 | find_package(CppCheck) 14 | 15 | # Add sub directories 16 | add_subdirectory(subproject1) 17 | add_subdirectory(subproject2) 18 | -------------------------------------------------------------------------------- /04-static-analysis/cppcheck-compile-commands/README.adoc: -------------------------------------------------------------------------------- 1 | = CppCheck Static Analysis using Compile Commands 2 | :toc: 3 | :toc-placement!: 4 | 5 | toc::[] 6 | 7 | # Introduction 8 | 9 | This example shows how to call the 10 | http://cppcheck.sourceforge.net/[CppCheck] tool to do static analysis. 11 | This shows how to use projects and a compile database. 12 | Projects are available from cppcheck v1.77 13 | 14 | It includes code to 15 | 16 | * Find the cppcheck binary 17 | * Generate an overall `make cppcheck-analysis` target to do static 18 | analysis on all sub-projects. 19 | 20 | The files included in this example are: 21 | 22 | ``` 23 | $ tree 24 | . 25 | ├── cmake 26 | │   └── modules 27 | │   └── FindCppCheck.cmake 28 | ├── CMakeLists.txt 29 | ├── subproject1 30 | │   ├── CMakeLists.txt 31 | │   └── main1.cpp 32 | └── subproject2 33 | ├── CMakeLists.txt 34 | └── main2.cpp 35 | ``` 36 | 37 | * link:CMakeLists.txt[] - Top level CMakeLists.txt 38 | * link:cmake/modules/FindCppCheck.cmake[] - A custom package module to find CppCheck 39 | * link:subproject1/CMakeLists.txt[] - CMake commands for subproject 1 40 | * link:subproject1/main1.cpp[] - source for a subproject with no errors 41 | * link:subproject2/CMakeLists.txt[] - CMake commands for subproject 2 42 | * link:subproject2/main2.cpp[] - source for a subproject that includes errors 43 | 44 | # Requirements 45 | 46 | To run this example you must have CppCheck of at least v1.77 installed. This is not 47 | available by default on Ubuntu but can be compiled using the following command. 48 | 49 | [source,bash] 50 | ---- 51 | $ wget https://github.com/danmar/cppcheck/archive/1.79.tar.gz \ 52 | && tar xvf 1.79.tar.gz \ 53 | && cd cppcheck-1.79 \ 54 | && mkdir build \ 55 | && cd build \ 56 | && cmake .. \ 57 | && sudo make install 58 | ---- 59 | 60 | # Concepts 61 | 62 | ## Adding Custom Package Modules 63 | 64 | As with the previous example I use a custom module to find CppCheck. This version is slightly different to the previous one and 65 | will automatically add a `make cppcheck-analysis` target. 66 | 67 | [source,cmake] 68 | ---- 69 | if(CPPCHECK_FOUND) 70 | file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/analysis/cppcheck) 71 | add_custom_target(cppcheck-analysis 72 | COMMAND ${CPPCHECK_COMMAND}) 73 | message("cppcheck found. Use cppccheck-analysis targets to run it") 74 | else() 75 | message("cppcheck not found. No cppccheck-analysis targets") 76 | endif() 77 | ---- 78 | 79 | The variables available have also changed. For full details on the commands see the `FindCppCheck.cmake` module. Below are a subset of the available options: 80 | 81 | ### Suppressions 82 | 83 | Adding a suppression file called `.cppcheck-suppressions` which must be in your +CMAKE_SOURCE_DIR+ 84 | 85 | ### Error Exitcode 86 | 87 | When cppcheck finds an error it can cause it to exit with a specific error. In this 88 | example, by default, it will exit with `1`. To change this you can set the 89 | +CPPCHECK_ERROR_EXITCODE_ARG+ argument when running CMake. 90 | 91 | ### Exitcode suppressions 92 | 93 | Sometimes you wish to display an error in the log, but to not have that error cause a failed build. To do this you can create a file `.cppcheck_exitcode_suppressions` and add suppressions to it. This file must be in your +CMAKE_SOURCE_DIR+ 94 | 95 | ### CppCheck arguments 96 | 97 | The default enabled checks are `--enabled=warning`. To change this you can override the `CPPCHECK_CHECK_ARGS` variable before calling `find(cppcheck)`. 98 | 99 | ### Excluding files / folders 100 | 101 | Many projects include some vendored 3rd party code. To exclude this from you check you can create a list `CPPCHECK_EXCLUDES` before calling the find module. This will add all files and folders in the list into the list of excluded folders. 102 | 103 | ### CppCheck build dir 104 | 105 | In this example, we set +CPPCHECK_BUILD_DIR_ARG+, to `${PROJECT_BINARY_DIR}/analysis/cppcheck`. This will output details of the build to this folder and can be used to 106 | increase the speed of rechecks if a file hasn't changed 107 | 108 | ## Compile Database 109 | 110 | CMake allows you to export all https://cmake.org/cmake/help/v3.5/variable/CMAKE_EXPORT_COMPILE_COMMANDS.html[compile commands] 111 | that are used to build the project into a file called `compile_commands.json` 112 | 113 | This can be done by setting the +CMAKE_EXPORT_COMPILE_COMMANDS+ variable to +ON+ 114 | as below: 115 | 116 | [source,cmake] 117 | ---- 118 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 119 | ---- 120 | 121 | The JSON file will look like: 122 | 123 | [source,json] 124 | ---- 125 | [ 126 | { 127 | "directory": "/home/user/development/project", 128 | "command": "/usr/bin/c++ ... -c ../foo/foo.cc", 129 | "file": "../foo/foo.cc" 130 | }, 131 | 132 | ... 133 | 134 | { 135 | "directory": "/home/user/development/project", 136 | "command": "/usr/bin/c++ ... -c ../foo/bar.cc", 137 | "file": "../foo/bar.cc" 138 | } 139 | ] 140 | ---- 141 | 142 | [NOTE] 143 | ==== 144 | This is only available for the `Makefile` and `ninja` generators. 145 | ==== 146 | 147 | ## CppCheck Projects 148 | 149 | Starting with CppCheck v1.77, you can pass the `--project` flag pointing to the 150 | compile database. This will cause CppCheck to run on al your cpp files using the same 151 | include directories and compiler flags as your normal build. 152 | 153 | [source,bash] 154 | ---- 155 | cppcheck --project=compile_comands.json 156 | ---- 157 | 158 | This will check all files in your project and sub-projects. There will be no analysis target per sub-project as with our previous example. 159 | 160 | # Building the example 161 | 162 | [source,bash] 163 | ---- 164 | $ mkdir build 165 | 166 | $ cd build/ 167 | 168 | $ cmake .. 169 | -- The C compiler identification is GNU 4.8.4 170 | -- The CXX compiler identification is GNU 4.8.4 171 | -- Check for working C compiler: /usr/bin/cc 172 | -- Check for working C compiler: /usr/bin/cc -- works 173 | -- Detecting C compiler ABI info 174 | -- Detecting C compiler ABI info - done 175 | -- Detecting C compile features 176 | -- Detecting C compile features - done 177 | -- Check for working CXX compiler: /usr/bin/c++ 178 | -- Check for working CXX compiler: /usr/bin/c++ -- works 179 | -- Detecting CXX compiler ABI info 180 | -- Detecting CXX compiler ABI info - done 181 | -- Detecting CXX compile features 182 | -- Detecting CXX compile features - done 183 | -- Found CPPCHECK: /usr/local/bin/cppcheck 184 | cppcheck found. Use cppccheck-analysis targets to run it 185 | -- Configuring done 186 | -- Generating done 187 | -- Build files have been written to: /data/code/04-static-analysis/cppcheck-compile-commands/build 188 | 189 | $ make cppcheck-analysis 190 | Scanning dependencies of target cppcheck-analysis 191 | [/data/code/04-static-analysis/cppcheck-compile-commands/subproject2/main2.cpp:7]: (error) Array 'tmp[10]' accessed at index 11, which is out of bounds. 192 | make[3]: *** [CMakeFiles/cppcheck-analysis] Error 1 193 | make[2]: *** [CMakeFiles/cppcheck-analysis.dir/all] Error 2 194 | make[1]: *** [CMakeFiles/cppcheck-analysis.dir/rule] Error 2 195 | make: *** [cppcheck-analysis] Error 2 196 | -------------------------------------------------------------------------------- /04-static-analysis/cppcheck-compile-commands/cmake/modules/FindCppCheck.cmake: -------------------------------------------------------------------------------- 1 | # Locate cppcheck 2 | # 3 | # This module defines 4 | # CPPCHECK_BIN, where to find cppcheck 5 | # 6 | # To help find the binary you can set CPPCHECK_ROOT_DIR to search a custom path 7 | # Exported argumets include 8 | # CPPCHECK_FOUND, if false, do not try to link to cppcheck --- if (CPPCHECK_FOUND) 9 | # 10 | # CPPCHECK_THREADS_ARG - Number of threads to use (e.g. -j 3) 11 | # CPPCHECK_PROJECT_ARG - The project to use (compile_comands.json) 12 | # CPPCHECK_BUILD_DIR_ARG - The build output directory 13 | # CPPCHECK_ERROR_EXITCODE_ARG - The exit code if an error is found 14 | # CPPCHECK_SUPPRESSIONS - A suppressiosn file to use 15 | # CPPCHECK_CHECKS_ARGS - The checks to run 16 | # CPPCHECK_OTHER_ARGS - Any other arguments 17 | # CPPCHECK_COMMAND - The full command to run the default cppcheck configuration 18 | # CPPCHECK_EXCLUDES - A list of files or folders to exclude from the scan. Must be the full path 19 | # 20 | # if CPPCHECK_XML_OUTPUT is set before calling this. CppCheck will create an xml file with that name 21 | # find the cppcheck binary 22 | 23 | # if custom path check there first 24 | if(CPPCHECK_ROOT_DIR) 25 | find_program(CPPCHECK_BIN 26 | NAMES 27 | cppcheck 28 | PATHS 29 | "${CPPCHECK_ROOT_DIR}" 30 | NO_DEFAULT_PATH) 31 | endif() 32 | 33 | find_program(CPPCHECK_BIN NAMES cppcheck) 34 | 35 | if(CPPCHECK_BIN) 36 | execute_process(COMMAND ${CPPCHECK_BIN} --version 37 | OUTPUT_VARIABLE CPPCHECK_VERSION 38 | ERROR_QUIET 39 | OUTPUT_STRIP_TRAILING_WHITESPACE) 40 | 41 | set(CPPCHECK_THREADS_ARG "-j4" CACHE STRING "The number of threads to use") 42 | set(CPPCHECK_PROJECT_ARG "--project=${PROJECT_BINARY_DIR}/compile_commands.json") 43 | set(CPPCHECK_BUILD_DIR_ARG "--cppcheck-build-dir=${PROJECT_BINARY_DIR}/analysis/cppcheck" CACHE STRING "The build directory to use") 44 | # Don't show these errors 45 | if(EXISTS "${CMAKE_SOURCE_DIR}/.cppcheck_suppressions") 46 | set(CPPCHECK_SUPPRESSIONS "--suppressions-list=${CMAKE_SOURCE_DIR}/.cppcheck_suppressions" CACHE STRING "The suppressions file to use") 47 | else() 48 | set(CPPCHECK_SUPPRESSIONS "" CACHE STRING "The suppressions file to use") 49 | endif() 50 | 51 | # Show these errors but don't fail the build 52 | # These are mainly going to be from the "warning" category that is enabled by default later 53 | if(EXISTS "${CMAKE_SOURCE_DIR}/.cppcheck_exitcode_suppressions") 54 | set(CPPCHECK_EXITCODE_SUPPRESSIONS "--exitcode-suppressions=${CMAKE_SOURCE_DIR}/.cppcheck_exitcode_suppressions" CACHE STRING "The exitcode suppressions file to use") 55 | else() 56 | set(CPPCHECK_EXITCODE_SUPPRESSIONS "" CACHE STRING "The exitcode suppressions file to use") 57 | endif() 58 | 59 | set(CPPCHECK_ERROR_EXITCODE_ARG "--error-exitcode=1" CACHE STRING "The exitcode to use if an error is found") 60 | set(CPPCHECK_CHECKS_ARGS "--enable=warning" CACHE STRING "Arguments for the checks to run") 61 | set(CPPCHECK_OTHER_ARGS "" CACHE STRING "Other arguments") 62 | set(_CPPCHECK_EXCLUDES) 63 | 64 | foreach(ex ${CPPCHECK_EXCLUDES}) 65 | list(APPEND _CPPCHECK_EXCLUDES "-i${ex}") 66 | endforeach(ex) 67 | 68 | set(CPPCHECK_ALL_ARGS 69 | ${CPPCHECK_THREADS_ARG} 70 | ${CPPCHECK_PROJECT_ARG} 71 | ${CPPCHECK_BUILD_DIR_ARG} 72 | ${CPPCHECK_ERROR_EXITCODE_ARG} 73 | ${CPPCHECK_SUPPRESSIONS} 74 | ${CPPCHECK_EXITCODE_SUPPRESSIONS} 75 | ${CPPCHECK_CHECKS_ARGS} 76 | ${CPPCHECK_OTHER_ARGS} 77 | ${_CPPCHECK_EXCLUDES} 78 | ) 79 | 80 | if(NOT CPPCHECK_XML_OUTPUT) 81 | set(CPPCHECK_COMMAND 82 | ${CPPCHECK_BIN} 83 | ${CPPCHECK_ALL_ARGS} 84 | ) 85 | else() 86 | set(CPPCHECK_COMMAND 87 | ${CPPCHECK_BIN} 88 | ${CPPCHECK_ALL_ARGS} 89 | --xml 90 | --xml-version=2 91 | 2> ${CPPCHECK_XML_OUTPUT}) 92 | endif() 93 | 94 | endif() 95 | 96 | 97 | 98 | # handle the QUIETLY and REQUIRED arguments and set YAMLCPP_FOUND to TRUE if all listed variables are TRUE 99 | include(FindPackageHandleStandardArgs) 100 | FIND_PACKAGE_HANDLE_STANDARD_ARGS( 101 | CPPCHECK 102 | DEFAULT_MSG 103 | CPPCHECK_BIN) 104 | 105 | mark_as_advanced( 106 | CPPCHECK_BIN 107 | CPPCHECK_THREADS_ARG 108 | CPPCHECK_PROJECT_ARG 109 | CPPCHECK_BUILD_DIR_ARG 110 | CPPCHECK_ERROR_EXITCODE_ARG 111 | CPPCHECK_SUPPRESSIONS 112 | CPPCHECK_CHECKS_ARGS 113 | CPPCHECK_OTHER_ARGS) 114 | 115 | if(CPPCHECK_FOUND) 116 | file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/analysis/cppcheck) 117 | add_custom_target(cppcheck-analysis 118 | COMMAND ${CPPCHECK_COMMAND}) 119 | message("cppcheck found. Use cppccheck-analysis targets to run it") 120 | else() 121 | message("cppcheck not found. No cppccheck-analysis targets") 122 | endif() 123 | -------------------------------------------------------------------------------- /04-static-analysis/cppcheck-compile-commands/run_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | mkdir -p build && cd build && cmake -DCPPCHECK_ERROR_EXITCODE_ARG="" .. && make cppcheck-analysis 3 | -------------------------------------------------------------------------------- /04-static-analysis/cppcheck-compile-commands/subproject1/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Set the project name 2 | project (subproject1) 3 | 4 | # Add an executable with the above sources 5 | add_executable(${PROJECT_NAME} main1.cpp) 6 | -------------------------------------------------------------------------------- /04-static-analysis/cppcheck-compile-commands/subproject1/main1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | std::cout << "Hello Main1!" << std::endl; 6 | return 0; 7 | } -------------------------------------------------------------------------------- /04-static-analysis/cppcheck-compile-commands/subproject2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Set the project name 2 | project (subproject2) 3 | 4 | # Add an executable with the above sources 5 | add_executable(${PROJECT_NAME} main2.cpp) 6 | -------------------------------------------------------------------------------- /04-static-analysis/cppcheck-compile-commands/subproject2/main2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | std::cout << "Hello Main2!" << std::endl; 6 | char tmp[10]; 7 | tmp[11] = 's'; 8 | return 0; 9 | } -------------------------------------------------------------------------------- /04-static-analysis/cppcheck/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.5) 2 | 3 | project(cppcheck_analysis) 4 | 5 | # Add a custom CMake Modules directory 6 | set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules 7 | ${CMAKE_MODULE_PATH}) 8 | 9 | # find the cppcheck binary 10 | find_package(CppCheck) 11 | 12 | # static analysis. Should be before adding subprojects 13 | set (ALL_ANALYSIS_TARGETS) 14 | 15 | # Add sub directories 16 | add_subdirectory(subproject1) 17 | add_subdirectory(subproject2) 18 | 19 | 20 | # Add the "make analysis" target 21 | if( CPPCHECK_FOUND ) 22 | add_custom_target(analysis) 23 | ADD_DEPENDENCIES(analysis ${ALL_ANALYSIS_TARGETS}) 24 | set_target_properties(analysis PROPERTIES EXCLUDE_FROM_ALL TRUE) 25 | message("analysis analysis targets are ${ALL_ANALYSIS_TARGETS}") 26 | endif() 27 | -------------------------------------------------------------------------------- /04-static-analysis/cppcheck/cmake/analysis.cmake: -------------------------------------------------------------------------------- 1 | # Make sure cppcheck binary is available 2 | if( NOT CPPCHECK_FOUND ) 3 | find_package(CppCheck) 4 | endif() 5 | 6 | # add a target for CppCheck 7 | # _target - The name of the project that this is for. Will generate ${_target}_analysis 8 | # _sources - The name of the variable holding the sources list. 9 | # This is the name of the variable not the actual list 10 | # 11 | # Macro instead of function to make the PARENT_SCOPE stuff easier 12 | macro(add_analysis _target _sources) 13 | if( CPPCHECK_FOUND ) 14 | 15 | # Get the include files to also feed to cppcheck 16 | get_property(dirs DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES) 17 | foreach(dir ${dirs}) 18 | LIST(APPEND cppcheck_includes "-I${dir}") 19 | endforeach() 20 | 21 | # Add to the all target to have a high level "make analysis" 22 | LIST(APPEND ALL_ANALYSIS_TARGETS "${_target}_analysis") 23 | set(ALL_ANALYSIS_TARGETS "${ALL_ANALYSIS_TARGETS}" PARENT_SCOPE) 24 | 25 | # This is used to make the command run correctly on the command line. 26 | # The COMMAND argument expects a list and this does the change 27 | # I need to check which version works with 2.7 28 | if (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VESION} GREATER 2.7) 29 | separate_arguments(tmp_args UNIX_COMMAND ${CPPCHECK_ARG}) 30 | else () 31 | # cmake 2.6 has different arguments 32 | string(REPLACE " " ";" tmp_args ${CPPCHECK_ARG}) 33 | endif () 34 | 35 | # add a custom _target_analysis target 36 | add_custom_target(${_target}_analysis) 37 | set_target_properties(${_target}_analysis PROPERTIES EXCLUDE_FROM_ALL TRUE) 38 | 39 | # add the cppcheck command to the target 40 | add_custom_command(TARGET ${_target}_analysis PRE_BUILD 41 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 42 | COMMAND ${CPPCHECK_BIN} ${tmp_args} ${cppcheck_includes} ${${_sources}} 43 | DEPENDS ${${_sources}} 44 | COMMENT "Running cppcheck: ${_target}" 45 | VERBATIM) 46 | message("adding cppcheck analysys target for ${_target}") 47 | endif() 48 | 49 | endmacro() 50 | 51 | -------------------------------------------------------------------------------- /04-static-analysis/cppcheck/cmake/modules/FindCppCheck.cmake: -------------------------------------------------------------------------------- 1 | # Locate cppcheck 2 | # 3 | # This module defines 4 | # CPPCHECK_FOUND, if false, do not try to link to cppcheck --- if (CPPCHECK_FOUND) 5 | # CPPCHECK_BIN, where to find cppcheck 6 | # 7 | # Exported argumets include 8 | # CPPCHECK_THREADS 9 | # CPPCHECK_ARG 10 | # 11 | # find the cppcheck binary 12 | find_program(CPPCHECK_BIN NAMES cppcheck) 13 | 14 | # 15 | # Arguments are 16 | # -j use multiple threads (and thread count) 17 | # --quite only show errors / warnings etc 18 | # --error-exitcode The code to exit with if an error shows up 19 | # --enabled Comma separated list of the check types. Can include warning,performance,style 20 | # Note nightly build on earth changes error-exitcode to 0 21 | set (CPPCHECK_THREADS "-j 4" CACHE STRING "The -j argument to have cppcheck use multiple threads / cores") 22 | 23 | set (CPPCHECK_ARG "${CPPCHECK_THREADS}" CACHE STRING "The arguments to pass to cppcheck. If set will overwrite CPPCHECK_THREADS") 24 | 25 | # handle the QUIETLY and REQUIRED arguments and set YAMLCPP_FOUND to TRUE if all listed variables are TRUE 26 | include(FindPackageHandleStandardArgs) 27 | FIND_PACKAGE_HANDLE_STANDARD_ARGS( 28 | CPPCHECK 29 | DEFAULT_MSG 30 | CPPCHECK_BIN 31 | CPPCHECK_THREADS 32 | CPPCHECK_ARG) 33 | 34 | mark_as_advanced( 35 | CPPCHECK_BIN 36 | CPPCHECK_THREADS 37 | CPPCHECK_ARG) 38 | -------------------------------------------------------------------------------- /04-static-analysis/cppcheck/run_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | mkdir -p build && cd build && cmake .. && make analysis 3 | -------------------------------------------------------------------------------- /04-static-analysis/cppcheck/subproject1/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Set the project name 2 | project (subproject1) 3 | 4 | # Create a sources variable with a link to all cpp files to compile 5 | set(SOURCES 6 | main1.cpp 7 | ) 8 | 9 | # include the file with the function then call the macro 10 | include(${CMAKE_SOURCE_DIR}/cmake/analysis.cmake) 11 | add_analysis(${PROJECT_NAME} SOURCES) 12 | 13 | # Add an executable with the above sources 14 | add_executable(${PROJECT_NAME} ${SOURCES}) -------------------------------------------------------------------------------- /04-static-analysis/cppcheck/subproject1/main1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | std::cout << "Hello Main1!" << std::endl; 6 | return 0; 7 | } -------------------------------------------------------------------------------- /04-static-analysis/cppcheck/subproject2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Set the project name 2 | project (subproject2) 3 | 4 | # Create a sources variable with a link to all cpp files to compile 5 | set(SOURCES 6 | main2.cpp 7 | ) 8 | 9 | # include the file with the function then call the macro 10 | include(${CMAKE_SOURCE_DIR}/cmake/analysis.cmake) 11 | add_analysis(${PROJECT_NAME} SOURCES) 12 | 13 | # Add an executable with the above sources 14 | add_executable(${PROJECT_NAME} ${SOURCES}) -------------------------------------------------------------------------------- /04-static-analysis/cppcheck/subproject2/main2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | std::cout << "Hello Main2!" << std::endl; 6 | char tmp[10]; 7 | tmp[11] = 's'; 8 | return 0; 9 | } -------------------------------------------------------------------------------- /05-unit-testing/README.adoc: -------------------------------------------------------------------------------- 1 | = Unit Testing 2 | 3 | :toc: 4 | :toc-placement!: 5 | 6 | toc::[] 7 | 8 | [[intro]] 9 | Introduction 10 | ------------ 11 | 12 | Unit testing is a software development process in which the smallest testable parts of an 13 | application, called units, are individually and independently scrutinized 14 | for proper operation. This can involve taking a class, function, or algorithm 15 | and writing test cases that can be run to verify that the unit is working correctly. 16 | 17 | CMake includes a tool called link:https://cmake.org/Wiki/CMake/Testing_With_CTest[CTest] 18 | which allows you to enable the `make test` target to run automated tests such as unit tests. 19 | 20 | There are many unit-testing frameworks available which can be used to help automate 21 | and ease the development of unit tests. In these examples I show how to use 22 | some of these frameworks and call them using the CMake testing utility CTest. 23 | 24 | The examples here include using the following frameworks: 25 | 26 | * http://www.boost.org/doc/libs/1_56_0/libs/test/doc/html/utf/user-guide.html[Boost Unit Test Framework] 27 | * https://github.com/google/googletest[Google Test - Download] 28 | * https://github.com/catchorg/Catch2[Catch2] 29 | -------------------------------------------------------------------------------- /05-unit-testing/boost/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | # Set the project name 4 | project (boost_unit_test) 5 | 6 | 7 | # find a boost install with the libraries unit_test_framework 8 | find_package(Boost 1.46.1 REQUIRED COMPONENTS unit_test_framework) 9 | 10 | # Add an library for the example classes 11 | add_library(example_boost_unit_test 12 | Reverse.cpp 13 | Palindrome.cpp 14 | ) 15 | 16 | target_include_directories(example_boost_unit_test 17 | PUBLIC 18 | ${CMAKE_CURRENT_SOURCE_DIR} 19 | ) 20 | 21 | target_link_libraries(example_boost_unit_test 22 | PUBLIC 23 | Boost::boost 24 | ) 25 | 26 | ############################################# 27 | # Unit tests 28 | 29 | # enable CTest testing 30 | enable_testing() 31 | 32 | # Add a testing executable 33 | add_executable(unit_tests unit_tests.cpp) 34 | 35 | target_link_libraries(unit_tests 36 | example_boost_unit_test 37 | Boost::unit_test_framework 38 | ) 39 | 40 | target_compile_definitions(unit_tests 41 | PRIVATE 42 | BOOST_TEST_DYN_LINK 43 | ) 44 | 45 | add_test(test_all unit_tests) 46 | -------------------------------------------------------------------------------- /05-unit-testing/boost/Palindrome.cpp: -------------------------------------------------------------------------------- 1 | #include "Palindrome.h" 2 | 3 | bool Palindrome::isPalindrome(const std::string& toCheck) 4 | { 5 | 6 | if (toCheck == std::string(toCheck.rbegin(), toCheck.rend())) { 7 | return true; 8 | } 9 | 10 | return false; 11 | } 12 | -------------------------------------------------------------------------------- /05-unit-testing/boost/Palindrome.h: -------------------------------------------------------------------------------- 1 | #ifndef __PALINDROME_H__ 2 | #define __PALINDROME_H__ 3 | 4 | #include 5 | 6 | /** 7 | * Trivial class to check if a string is a palindrome. 8 | */ 9 | class Palindrome 10 | { 11 | public: 12 | bool isPalindrome(const std::string& toCheck); 13 | }; 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /05-unit-testing/boost/README.adoc: -------------------------------------------------------------------------------- 1 | = Boost Unit Testing Framework 2 | :toc: 3 | :toc-placement!: 4 | 5 | toc::[] 6 | 7 | 8 | # Introduction 9 | 10 | Using link:https://cmake.org/Wiki/CMake/Testing_With_CTest[CTest] you can generate 11 | a `make test` target to run automated unit-tests. This example shows how to 12 | find the link:http://www.boost.org/doc/libs/1_56_0/libs/test/doc/html/utf/user-guide.html[boost unit-test-framework], 13 | create tests and run them. 14 | 15 | The files in this tutorial are below: 16 | 17 | ``` 18 | $ tree 19 | . 20 | ├── CMakeLists.txt 21 | ├── Reverse.h 22 | ├── Reverse.cpp 23 | ├── Palindrome.h 24 | ├── Palindrome.cpp 25 | ├── unit_tests.cpp 26 | ``` 27 | 28 | * link:CMakeLists.txt[] - Contains the CMake commands you wish to run 29 | * link:Reverse.h[] / link:Reverse.cpp[.cpp] - Class to reverse a string 30 | * link:Palindrome.h[] / link:Palindrome.cpp[.cpp] - Class to test if a string is a palindrome 31 | * link:unit_test.cpp[] - Unit Tests using boost unit test framework 32 | 33 | # Requirements 34 | 35 | This example requires the boost libraries to be installed in a default system 36 | location. The library in use is the boost unit-test-framework. 37 | 38 | # Concepts 39 | 40 | ## Enabling testing 41 | 42 | To enable testing you must include the following line in your top level CMakeLists.txt 43 | 44 | [source,cmake] 45 | ---- 46 | enable_testing() 47 | ---- 48 | 49 | This will enable testing for the current folder and all folders below it. 50 | 51 | ## Adding a testing executable 52 | 53 | The requirement for this step will depend on your unit-test framework. In the example 54 | of boost, you can create binary(s) which includes all the unit tests that you want to run. 55 | 56 | [source,cmake] 57 | ---- 58 | add_executable(unit_tests unit_tests.cpp) 59 | 60 | target_link_libraries(unit_tests 61 | example_boost_unit_test 62 | Boost::unit_test_framework 63 | ) 64 | 65 | target_compile_definitions(unit_tests 66 | PRIVATE 67 | BOOST_TEST_DYN_LINK 68 | ) 69 | ---- 70 | 71 | In the above code, a unit test binary is added, which links against the boost unit-test-framework 72 | and includes a definition to tell it that we are using dynamic linking. 73 | 74 | ## Add A test 75 | 76 | To add a test you call the link:https://cmake.org/cmake/help/v3.0/command/add_test.html[`add_test()`] function. 77 | This will create a named test which will run the supplied command. 78 | 79 | [source,cmake] 80 | ---- 81 | add_test(test_all unit_tests) 82 | ---- 83 | 84 | In this example, we create a test called `test_all` which will run the executable 85 | created by the `unit_tests` executable created from the call to `add_executable` 86 | 87 | # Building the Example 88 | 89 | [source,bash] 90 | ---- 91 | $ mkdir build 92 | 93 | $ cd build/ 94 | 95 | $ cmake .. 96 | -- The C compiler identification is GNU 4.8.4 97 | -- The CXX compiler identification is GNU 4.8.4 98 | -- Check for working C compiler: /usr/bin/cc 99 | -- Check for working C compiler: /usr/bin/cc -- works 100 | -- Detecting C compiler ABI info 101 | -- Detecting C compiler ABI info - done 102 | -- Check for working CXX compiler: /usr/bin/c++ 103 | -- Check for working CXX compiler: /usr/bin/c++ -- works 104 | -- Detecting CXX compiler ABI info 105 | -- Detecting CXX compiler ABI info - done 106 | -- Boost version: 1.54.0 107 | -- Found the following Boost libraries: 108 | -- unit_test_framework 109 | -- Configuring done 110 | -- Generating done 111 | -- Build files have been written to: /home/matrim/workspace/cmake-examples/05-unit-testing/boost/build 112 | 113 | $ make 114 | Scanning dependencies of target example_boost_unit_test 115 | [ 33%] Building CXX object CMakeFiles/example_boost_unit_test.dir/Reverse.cpp.o 116 | [ 66%] Building CXX object CMakeFiles/example_boost_unit_test.dir/Palindrome.cpp.o 117 | Linking CXX static library libexample_boost_unit_test.a 118 | [ 66%] Built target example_boost_unit_test 119 | Scanning dependencies of target unit_tests 120 | [100%] Building CXX object CMakeFiles/unit_tests.dir/unit_tests.cpp.o 121 | Linking CXX executable unit_tests 122 | [100%] Built target unit_tests 123 | 124 | $ make test 125 | Running tests... 126 | Test project /home/matrim/workspace/cmake-examples/05-unit-testing/boost/build 127 | Start 1: test_all 128 | 1/1 Test #1: test_all ......................... Passed 0.00 sec 129 | 130 | 100% tests passed, 0 tests failed out of 1 131 | 132 | Total Test time (real) = 0.01 sec 133 | ---- 134 | 135 | If the code is changed and it causes the unit tests to produce an error. 136 | Then when running the tests you will see the following output. 137 | 138 | [source,bash] 139 | ---- 140 | $ make test 141 | Running tests... 142 | Test project /home/matrim/workspace/cmake-examples/05-unit-testing/boost/build 143 | Start 1: test_all 144 | 1/1 Test #1: test_all .........................***Failed 0.00 sec 145 | 146 | 0% tests passed, 1 tests failed out of 1 147 | 148 | Total Test time (real) = 0.00 sec 149 | 150 | The following tests FAILED: 151 | 1 - test_all (Failed) 152 | Errors while running CTest 153 | make: *** [test] Error 8 154 | 155 | ---- 156 | -------------------------------------------------------------------------------- /05-unit-testing/boost/Reverse.cpp: -------------------------------------------------------------------------------- 1 | #include "Reverse.h" 2 | 3 | std::string Reverse::reverse(std::string& toReverse) 4 | { 5 | std::string ret; 6 | 7 | for(std::string::reverse_iterator rit=toReverse.rbegin(); rit!=toReverse.rend(); ++rit) 8 | { 9 | ret.insert(ret.end(), *rit); 10 | } 11 | return ret; 12 | } 13 | -------------------------------------------------------------------------------- /05-unit-testing/boost/Reverse.h: -------------------------------------------------------------------------------- 1 | #ifndef __REVERSE_H__ 2 | #define __REVERSE_H__ 3 | 4 | #include 5 | 6 | /** 7 | * Trivial class whose only function is to reverse a string. 8 | * Should use std::reverse instead but want to have example with own class 9 | */ 10 | class Reverse 11 | { 12 | public: 13 | std::string reverse(std::string& toReverse); 14 | }; 15 | #endif 16 | -------------------------------------------------------------------------------- /05-unit-testing/boost/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | std::cout << "Hello Third Party Include!" << std::endl; 8 | 9 | // use a shared ptr 10 | boost::shared_ptr isp(new int(4)); 11 | 12 | // trivial use of boost filesystem 13 | boost::filesystem::path path = "/usr/share/cmake/modules"; 14 | if(path.is_relative()) 15 | { 16 | std::cout << "Path is relative" << std::endl; 17 | } 18 | else 19 | { 20 | std::cout << "Path is not relative" << std::endl; 21 | } 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /05-unit-testing/boost/post_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | make test 4 | -------------------------------------------------------------------------------- /05-unit-testing/boost/unit_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Reverse.h" 3 | #include "Palindrome.h" 4 | 5 | #define BOOST_TEST_MODULE VsidCommonTest 6 | #include 7 | 8 | BOOST_AUTO_TEST_SUITE( reverse_tests ) 9 | 10 | BOOST_AUTO_TEST_CASE( simple ) 11 | { 12 | std::string toRev = "Hello"; 13 | 14 | Reverse rev; 15 | std::string res = rev.reverse(toRev); 16 | 17 | BOOST_CHECK_EQUAL( res, "olleH" ); 18 | 19 | } 20 | 21 | 22 | BOOST_AUTO_TEST_CASE( empty ) 23 | { 24 | std::string toRev; 25 | 26 | Reverse rev; 27 | std::string res = rev.reverse(toRev); 28 | 29 | BOOST_CHECK_EQUAL( res, "" ); 30 | } 31 | 32 | BOOST_AUTO_TEST_SUITE_END() 33 | 34 | 35 | BOOST_AUTO_TEST_SUITE( palindrome_tests ) 36 | 37 | BOOST_AUTO_TEST_CASE( is_palindrome ) 38 | { 39 | std::string pal = "mom"; 40 | Palindrome pally; 41 | 42 | BOOST_CHECK_EQUAL( pally.isPalindrome(pal), true ); 43 | 44 | } 45 | 46 | BOOST_AUTO_TEST_SUITE_END() 47 | -------------------------------------------------------------------------------- /05-unit-testing/catch2-vendored/3rd_party/catch2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(catch2) 4 | 5 | # Prepare "Catch2" library for other executables 6 | add_library(Catch2 INTERFACE) 7 | add_library(Catch2::Test ALIAS Catch2) 8 | target_include_directories(Catch2 INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) 9 | -------------------------------------------------------------------------------- /05-unit-testing/catch2-vendored/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | # Set the project name 4 | project (catch2_unit_test) 5 | 6 | 7 | set(CMAKE_CXX_STANDARD 11) 8 | 9 | # add the CMakeFile that defines catch2 10 | add_subdirectory(3rd_party/catch2) 11 | 12 | # Add an library for the example classes 13 | add_library(example_unit_test 14 | Reverse.cpp 15 | Palindrome.cpp 16 | ) 17 | 18 | 19 | ############################################# 20 | # Unit tests 21 | 22 | # enable CTest testing 23 | enable_testing() 24 | 25 | # Add a testing executable 26 | add_executable(unit_tests unit_tests.cpp) 27 | 28 | target_link_libraries(unit_tests 29 | example_unit_test 30 | Catch2::Test 31 | ) 32 | 33 | add_test(test_all unit_tests) 34 | -------------------------------------------------------------------------------- /05-unit-testing/catch2-vendored/Palindrome.cpp: -------------------------------------------------------------------------------- 1 | #include "Palindrome.h" 2 | 3 | bool Palindrome::isPalindrome(const std::string& toCheck) 4 | { 5 | 6 | if (toCheck == std::string(toCheck.rbegin(), toCheck.rend())) { 7 | return true; 8 | } 9 | 10 | return false; 11 | } 12 | -------------------------------------------------------------------------------- /05-unit-testing/catch2-vendored/Palindrome.h: -------------------------------------------------------------------------------- 1 | #ifndef __PALINDROME_H__ 2 | #define __PALINDROME_H__ 3 | 4 | #include 5 | 6 | /** 7 | * Trivial class to check if a string is a palindrome. 8 | */ 9 | class Palindrome 10 | { 11 | public: 12 | bool isPalindrome(const std::string& toCheck); 13 | }; 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /05-unit-testing/catch2-vendored/README.adoc: -------------------------------------------------------------------------------- 1 | = Catch2 Unit Testing Framework 2 | :toc: 3 | :toc-placement!: 4 | 5 | toc::[] 6 | 7 | 8 | # Introduction 9 | 10 | Using link:https://cmake.org/Wiki/CMake/Testing_With_CTest[CTest] you can generate 11 | a `make test` target to run automated unit-tests. This example shows how to 12 | find the https://github.com/catchorg/Catch2[catch2 framework], 13 | create tests and run them. 14 | 15 | The files in this tutorial are below: 16 | 17 | ``` 18 | $ tree 19 | . 20 | ├── 3rd_party 21 | │   └── catch2 22 | │   ├── catch2 23 | │   │   └── catch.hpp 24 | │   └── CMakeLists.txt 25 | ├── CMakeLists.txt 26 | ├── Reverse.h 27 | ├── Reverse.cpp 28 | ├── Palindrome.h 29 | ├── Palindrome.cpp 30 | ├── unit_tests.cpp 31 | ``` 32 | 33 | * link:3rd_party/catch2/catch2/catch.hpp[] - Vendored copy of the https://github.com/catchorg/Catch2/blob/v2.5.0/single_include/catch2/catch.hpp[single header version of catch2] 34 | * link:3rd_party/catch2/CMakeLists.txt[] - CMake file to make Catch2 available as a library 35 | * link:CMakeLists.txt[] - Contains the CMake commands you wish to run 36 | * link:Reverse.h[] / link:Reverse.cpp[.cpp] - Class to reverse a string 37 | * link:Palindrome.h[] / link:Palindrome.cpp[.cpp] - Class to test if a string is a palindrome 38 | * link:unit_test.cpp[] - Unit Tests using catch2 unit test framework 39 | 40 | # Requirements 41 | 42 | A C++11 compatible compiler 43 | 44 | # Concepts 45 | 46 | ## Vendoring catch2 47 | 48 | As catch2 is available as a single header file I have downloaded it and checked it into my repository. This mean 49 | that I don't have any external dependencies when building my project. This is one of the 50 | https://github.com/catchorg/Catch2/blob/master/docs/tutorial.md#getting-catch2[simplest] ways to use Catch2. 51 | 52 | ## Catch2 Interface Library 53 | 54 | The CMakeLists in the catch2 directory creates an `INTERFACE` library and `ALIAS` library to make it 55 | easy to add Catch2 to your executable. 56 | 57 | [source,cmake] 58 | ---- 59 | add_library(Catch2 INTERFACE) 60 | add_library(Catch2::Test ALIAS Catch2) 61 | target_include_directories(Catch2 INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) 62 | ---- 63 | 64 | ## Build with C++11 65 | 66 | As Catch2 requires C++11 to build, I have used the `CMAKE_CXX_STANDARD` to set C++11. As described 67 | in earlier examples you can use other methods to set this standard. 68 | 69 | ## Enabling testing 70 | 71 | To enable testing you must include the following line in your top level CMakeLists.txt 72 | 73 | [source,cmake] 74 | ---- 75 | enable_testing() 76 | ---- 77 | 78 | This will enable testing for the current folder and all folders below it. 79 | 80 | ## Adding a testing executable 81 | 82 | The requirement for this step will depend on your unit-test framework. In the example 83 | of catch2, you can create binary(s) which includes all the unit tests that you want to run. 84 | 85 | [source,cmake] 86 | ---- 87 | add_executable(unit_tests unit_tests.cpp) 88 | 89 | target_link_libraries(unit_tests 90 | example_unit_test 91 | Catch2::Test 92 | ) 93 | ---- 94 | 95 | In the above code, a unit test binary is added, which links against the catch2 `ALIAS` target created earlier. 96 | 97 | ## Add A test 98 | 99 | To add a test you call the link:https://cmake.org/cmake/help/v3.0/command/add_test.html[`add_test()`] function. 100 | This will create a named test which will run the supplied command. 101 | 102 | [source,cmake] 103 | ---- 104 | add_test(test_all unit_tests) 105 | ---- 106 | 107 | In this example, we create a test called `test_all` which will run the executable 108 | created by the `unit_tests` executable created from the call to `add_executable` 109 | 110 | # Building the Example 111 | 112 | [source,bash] 113 | ---- 114 | $ mkdir build 115 | 116 | $ cd build/ 117 | 118 | $ cmake .. 119 | -- The C compiler identification is GNU 5.4.0 120 | -- The CXX compiler identification is GNU 5.4.0 121 | -- Check for working C compiler: /usr/bin/cc 122 | -- Check for working C compiler: /usr/bin/cc -- works 123 | -- Detecting C compiler ABI info 124 | -- Detecting C compiler ABI info - done 125 | -- Detecting C compile features 126 | -- Detecting C compile features - done 127 | -- Check for working CXX compiler: /usr/bin/c++ 128 | -- Check for working CXX compiler: /usr/bin/c++ -- works 129 | -- Detecting CXX compiler ABI info 130 | -- Detecting CXX compiler ABI info - done 131 | -- Detecting CXX compile features 132 | -- Detecting CXX compile features - done 133 | -- Configuring done 134 | -- Generating done 135 | -- Build files have been written to: /data/code/cmake-examples/05-unit-testing/catch2-vendored/build 136 | 137 | 138 | $ make 139 | Scanning dependencies of target example_unit_test 140 | [ 20%] Building CXX object CMakeFiles/example_unit_test.dir/Reverse.cpp.o 141 | [ 40%] Building CXX object CMakeFiles/example_unit_test.dir/Palindrome.cpp.o 142 | [ 60%] Linking CXX static library libexample_unit_test.a 143 | [ 60%] Built target example_unit_test 144 | Scanning dependencies of target unit_tests 145 | [ 80%] Building CXX object CMakeFiles/unit_tests.dir/unit_tests.cpp.o 146 | [100%] Linking CXX executable unit_tests 147 | [100%] Built target unit_tests 148 | 149 | 150 | $ make test 151 | Running tests... 152 | Test project /data/code/cmake-examples/05-unit-testing/catch2-vendored/build 153 | Start 1: test_all 154 | 1/1 Test #1: test_all ......................... Passed 0.00 sec 155 | 156 | 100% tests passed, 0 tests failed out of 1 157 | 158 | Total Test time (real) = 0.00 sec 159 | ---- 160 | 161 | If the code is changed and it causes the unit tests to produce an error. 162 | Then when running the tests you will see the following output. 163 | 164 | [source,bash] 165 | ---- 166 | Running tests... 167 | Test project /data/code/cmake-examples/05-unit-testing/catch2-vendored/build 168 | Start 1: test_all 169 | 1/1 Test #1: test_all .........................***Failed 0.00 sec 170 | 171 | 0% tests passed, 1 tests failed out of 1 172 | 173 | Total Test time (real) = 0.00 sec 174 | 175 | The following tests FAILED: 176 | 1 - test_all (Failed) 177 | Errors while running CTest 178 | Makefile:61: recipe for target 'test' failed 179 | make: *** [test] Error 8 180 | ---- 181 | -------------------------------------------------------------------------------- /05-unit-testing/catch2-vendored/Reverse.cpp: -------------------------------------------------------------------------------- 1 | #include "Reverse.h" 2 | 3 | std::string Reverse::reverse(std::string& toReverse) 4 | { 5 | std::string ret; 6 | 7 | for(std::string::reverse_iterator rit=toReverse.rbegin(); rit!=toReverse.rend(); ++rit) 8 | { 9 | ret.insert(ret.end(), *rit); 10 | } 11 | return ret; 12 | } 13 | -------------------------------------------------------------------------------- /05-unit-testing/catch2-vendored/Reverse.h: -------------------------------------------------------------------------------- 1 | #ifndef __REVERSE_H__ 2 | #define __REVERSE_H__ 3 | 4 | #include 5 | 6 | /** 7 | * Trivial class whose only function is to reverse a string. 8 | * Should use std::reverse instead but want to have example with own class 9 | */ 10 | class Reverse 11 | { 12 | public: 13 | std::string reverse(std::string& toReverse); 14 | }; 15 | #endif 16 | -------------------------------------------------------------------------------- /05-unit-testing/catch2-vendored/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | std::cout << "Hello Third Party Include!" << std::endl; 8 | 9 | // use a shared ptr 10 | boost::shared_ptr isp(new int(4)); 11 | 12 | // trivial use of boost filesystem 13 | boost::filesystem::path path = "/usr/share/cmake/modules"; 14 | if(path.is_relative()) 15 | { 16 | std::cout << "Path is relative" << std::endl; 17 | } 18 | else 19 | { 20 | std::cout << "Path is not relative" << std::endl; 21 | } 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /05-unit-testing/catch2-vendored/post_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | make test 4 | -------------------------------------------------------------------------------- /05-unit-testing/catch2-vendored/unit_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Reverse.h" 3 | #include "Palindrome.h" 4 | 5 | #define CATCH_CONFIG_MAIN 6 | #include "catch2/catch.hpp" 7 | 8 | 9 | TEST_CASE( "simple" ) 10 | { 11 | std::string toRev = "Hello"; 12 | 13 | Reverse rev; 14 | std::string res = rev.reverse(toRev); 15 | 16 | REQUIRE( res == "olleH" ); 17 | } 18 | 19 | TEST_CASE( "empty" ) 20 | { 21 | std::string toRev; 22 | 23 | Reverse rev; 24 | std::string res = rev.reverse(toRev); 25 | 26 | REQUIRE( res == "" ); 27 | } 28 | 29 | TEST_CASE( "is_palindrome" ) 30 | { 31 | std::string pal = "mom"; 32 | Palindrome pally; 33 | 34 | REQUIRE( pally.isPalindrome(pal) == true ); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /05-unit-testing/google-test-download/3rd_party/google-test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Download and unpack googletest at configure time 2 | # See: http://crascit.com/2015/07/25/cmake-gtest/ 3 | configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt) 4 | # Call CMake to download and Google Test 5 | execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . 6 | RESULT_VARIABLE result 7 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download ) 8 | if(result) 9 | message(FATAL_ERROR "CMake step for googletest failed: ${result}") 10 | endif() 11 | # Build the downloaded google test 12 | execute_process(COMMAND ${CMAKE_COMMAND} --build . 13 | RESULT_VARIABLE result 14 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download ) 15 | if(result) 16 | message(FATAL_ERROR "Build step for googletest failed: ${result}") 17 | endif() 18 | 19 | # Prevent overriding the parent project's compiler/linker 20 | # settings on Windows 21 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 22 | # Prevent installation of GTest with your project 23 | set(INSTALL_GTEST OFF CACHE BOOL "" FORCE) 24 | set(INSTALL_GMOCK OFF CACHE BOOL "" FORCE) 25 | 26 | # Add googletest directly to our build. This defines 27 | # the gtest and gtest_main targets. 28 | add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src 29 | ${CMAKE_CURRENT_BINARY_DIR}/googletest-build) 30 | 31 | # This is a bit of a hack that can be used to get gtest libraries to build in C++11 if you aren't using CMAKE_CXX_STANDARD 32 | # 33 | #set(CXX11_FEATURES 34 | # cxx_nullptr 35 | # cxx_auto_type 36 | # cxx_delegating_constructors 37 | #) 38 | #target_compile_features(gtest 39 | # PRIVATE 40 | # ${CXX11_FEATURES} 41 | #) 42 | # 43 | #target_compile_features(gmock_main 44 | # PRIVATE 45 | # ${CXX11_FEATURES} 46 | #) 47 | # 48 | #target_compile_features(gmock 49 | # PRIVATE 50 | # ${CXX11_FEATURES} 51 | #) 52 | # 53 | #target_compile_features(gmock_main 54 | # PRIVATE 55 | # ${CXX11_FEATURES} 56 | #) 57 | 58 | # Add aliases for GTest and GMock libraries 59 | if(NOT TARGET GTest::GTest) 60 | add_library(GTest::GTest ALIAS gtest) 61 | add_library(GTest::Main ALIAS gtest_main) 62 | endif() 63 | 64 | if(NOT TARGET GTest::GMock) 65 | add_library(GMock::GMock ALIAS gmock) 66 | add_library(GMock::Main ALIAS gmock_main) 67 | endif() 68 | 69 | -------------------------------------------------------------------------------- /05-unit-testing/google-test-download/3rd_party/google-test/CMakeLists.txt.in: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(googletest-download NONE) 4 | 5 | include(ExternalProject) 6 | 7 | # Version bfc0ffc8a698072c794ae7299db9cb6866f4c0bc happens to be master when I set this up. 8 | # To prevent an issue with accidentally installing GTest / GMock with your project you should use a 9 | # commit after 9469fb687d040b60c8749b7617fee4e77c7f6409 10 | # Note: This is after the release of v1.8 11 | ExternalProject_Add(googletest 12 | URL https://github.com/google/googletest/archive/bfc0ffc8a698072c794ae7299db9cb6866f4c0bc.tar.gz 13 | SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" 14 | BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" 15 | CONFIGURE_COMMAND "" 16 | BUILD_COMMAND "" 17 | INSTALL_COMMAND "" 18 | TEST_COMMAND "" 19 | ) 20 | -------------------------------------------------------------------------------- /05-unit-testing/google-test-download/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | # Set the project name 4 | project (google_test_example) 5 | 6 | # Add an library for the example classes 7 | add_library(example_google_test 8 | Reverse.cpp 9 | Palindrome.cpp 10 | ) 11 | 12 | 13 | ############################################# 14 | # Unit tests 15 | 16 | add_subdirectory(3rd_party/google-test) 17 | 18 | # enable CTest testing 19 | enable_testing() 20 | 21 | # Add a testing executable 22 | add_executable(unit_tests unit_tests.cpp) 23 | 24 | target_link_libraries(unit_tests 25 | example_google_test 26 | GTest::GTest 27 | GTest::Main 28 | ) 29 | 30 | add_test(test_all unit_tests) 31 | -------------------------------------------------------------------------------- /05-unit-testing/google-test-download/Palindrome.cpp: -------------------------------------------------------------------------------- 1 | #include "Palindrome.h" 2 | 3 | bool Palindrome::isPalindrome(const std::string& toCheck) 4 | { 5 | 6 | if (toCheck == std::string(toCheck.rbegin(), toCheck.rend())) { 7 | return true; 8 | } 9 | 10 | return false; 11 | } 12 | -------------------------------------------------------------------------------- /05-unit-testing/google-test-download/Palindrome.h: -------------------------------------------------------------------------------- 1 | #ifndef __PALINDROME_H__ 2 | #define __PALINDROME_H__ 3 | 4 | #include 5 | 6 | /** 7 | * Trivial class to check if a string is a palindrome. 8 | */ 9 | class Palindrome 10 | { 11 | public: 12 | bool isPalindrome(const std::string& toCheck); 13 | }; 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /05-unit-testing/google-test-download/Reverse.cpp: -------------------------------------------------------------------------------- 1 | #include "Reverse.h" 2 | 3 | std::string Reverse::reverse(std::string& toReverse) 4 | { 5 | std::string ret; 6 | 7 | for(std::string::reverse_iterator rit=toReverse.rbegin(); rit!=toReverse.rend(); ++rit) 8 | { 9 | ret.insert(ret.end(), *rit); 10 | } 11 | return ret; 12 | } 13 | -------------------------------------------------------------------------------- /05-unit-testing/google-test-download/Reverse.h: -------------------------------------------------------------------------------- 1 | #ifndef __REVERSE_H__ 2 | #define __REVERSE_H__ 3 | 4 | #include 5 | 6 | /** 7 | * Trivial class whose only function is to reverse a string. 8 | * Should use std::reverse instead but want to have example with own class 9 | */ 10 | class Reverse 11 | { 12 | public: 13 | std::string reverse(std::string& toReverse); 14 | }; 15 | #endif 16 | -------------------------------------------------------------------------------- /05-unit-testing/google-test-download/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | std::cout << "Hello Third Party Include!" << std::endl; 8 | 9 | // use a shared ptr 10 | boost::shared_ptr isp(new int(4)); 11 | 12 | // trivial use of boost filesystem 13 | boost::filesystem::path path = "/usr/share/cmake/modules"; 14 | if(path.is_relative()) 15 | { 16 | std::cout << "Path is relative" << std::endl; 17 | } 18 | else 19 | { 20 | std::cout << "Path is not relative" << std::endl; 21 | } 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /05-unit-testing/google-test-download/post_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Disabled for now because of issue with libcurl and https" 4 | exit 0 5 | 6 | #make test 7 | -------------------------------------------------------------------------------- /05-unit-testing/google-test-download/run_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Disabled for now because of issue with libcurl and https" 4 | exit 0 5 | -------------------------------------------------------------------------------- /05-unit-testing/google-test-download/unit_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Reverse.h" 3 | #include "Palindrome.h" 4 | 5 | #include 6 | 7 | class ReverseTests : public ::testing::Test 8 | { 9 | }; 10 | 11 | TEST_F(ReverseTests, simple ) 12 | { 13 | std::string toRev = "Hello"; 14 | 15 | Reverse rev; 16 | std::string res = rev.reverse(toRev); 17 | 18 | EXPECT_EQ(res, "olleH" ); 19 | 20 | } 21 | 22 | TEST_F(ReverseTests, empty ) 23 | { 24 | std::string toRev; 25 | 26 | Reverse rev; 27 | std::string res = rev.reverse(toRev); 28 | 29 | EXPECT_EQ(res, "" ); 30 | } 31 | 32 | TEST_F(ReverseTests, is_palindrome ) 33 | { 34 | std::string pal = "mom"; 35 | Palindrome pally; 36 | 37 | EXPECT_TRUE(pally.isPalindrome(pal)); 38 | 39 | } 40 | -------------------------------------------------------------------------------- /06-installer/README.adoc: -------------------------------------------------------------------------------- 1 | = Installers 2 | 3 | :toc: 4 | :toc-placement!: 5 | 6 | toc::[] 7 | 8 | [[intro]] 9 | Introduction 10 | ------------ 11 | 12 | CMake has the ability to create installers for multiple platforms using a program 13 | called link:https://cmake.org/Wiki/CMake:CPackPackageGenerators[CPack]. 14 | CPack includes the ability to create Linux RPM, deb and gzip distributions 15 | of both binaries and source code. It also includes the ability to create NSIS files for Microsoft Windows. 16 | -------------------------------------------------------------------------------- /06-installer/deb/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(cmake_examples_deb) 4 | 5 | # set a project version 6 | set (deb_example_VERSION_MAJOR 0) 7 | set (deb_example_VERSION_MINOR 2) 8 | set (deb_example_VERSION_PATCH 2) 9 | set (deb_example_VERSION "${deb_example_VERSION_MAJOR}.${deb_example_VERSION_MINOR}.${deb_example_VERSION_PATCH}") 10 | 11 | 12 | ############################################################ 13 | # Create a library 14 | ############################################################ 15 | 16 | #Generate the shared library from the library sources 17 | add_library(cmake_examples_deb SHARED src/Hello.cpp) 18 | 19 | target_include_directories(cmake_examples_deb 20 | PUBLIC 21 | ${PROJECT_SOURCE_DIR}/include 22 | ) 23 | ############################################################ 24 | # Create an executable 25 | ############################################################ 26 | 27 | # Add an executable with the above sources 28 | add_executable(cmake_examples_deb_bin src/main.cpp) 29 | 30 | # link the new hello_library target with the hello_binary target 31 | target_link_libraries( cmake_examples_deb_bin 32 | PUBLIC 33 | cmake_examples_deb 34 | ) 35 | 36 | ############################################################ 37 | # Install 38 | ############################################################ 39 | 40 | # Binaries 41 | install (TARGETS cmake_examples_deb_bin 42 | DESTINATION bin) 43 | 44 | # Library 45 | # Note: may not work on windows 46 | install (TARGETS cmake_examples_deb 47 | LIBRARY DESTINATION lib) 48 | 49 | # Config 50 | install (FILES cmake-examples.conf 51 | DESTINATION etc) 52 | 53 | ############################################################ 54 | # Create DEB 55 | ############################################################ 56 | 57 | # Tell CPack to generate a .deb package 58 | set(CPACK_GENERATOR "DEB") 59 | 60 | # Set a Package Maintainer. 61 | # This is required 62 | set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Thom Troy") 63 | 64 | # Set a Package Version 65 | set(CPACK_PACKAGE_VERSION ${deb_example_VERSION}) 66 | 67 | # Include CPack 68 | include(CPack) 69 | -------------------------------------------------------------------------------- /06-installer/deb/README.adoc: -------------------------------------------------------------------------------- 1 | = Creating deb files 2 | :toc: 3 | :toc-placement!: 4 | 5 | toc::[] 6 | 7 | # Introduction 8 | 9 | This example shows how to generate a Linux installers using the link:https://www.debian.org/doc/manuals/debian-faq/ch-pkg_basics.en.html[deb] 10 | format. 11 | 12 | The files in this tutorial are below: 13 | 14 | ``` 15 | $ tree 16 | . 17 | ├── cmake-examples.conf 18 | ├── CMakeLists.txt 19 | ├── include 20 | │   └── Hello.h 21 | └── src 22 | ├── Hello.cpp 23 | └── main.cpp 24 | ``` 25 | 26 | * link:CMakeLists.txt[] - Contains the CMake commands you wish to run 27 | * link:cmake-examples.conf[] - An example configuration file 28 | * link:include/Hello.h[] - The header file to include 29 | * link:src/Hello.cpp[] - A source file to compile 30 | * link:src/main.cpp[] - The source file with main 31 | 32 | # Concepts 33 | 34 | ## CPack Generator 35 | 36 | A CPack Generator can be used by a `make package` target to create an installer. 37 | 38 | In the case of Debian packages you can tell CMake to create a generator using the following: 39 | 40 | [source,cmake] 41 | ---- 42 | set(CPACK_GENERATOR "DEB") 43 | ---- 44 | 45 | After setting various settings to describe the package you must then tell CMake to 46 | include the CPack generator using 47 | 48 | [source,cmake] 49 | ---- 50 | include(CPack) 51 | ---- 52 | 53 | Once included all files that would typically be installed using a `make install` target 54 | can now be packaged into a Debian package. 55 | 56 | ## Debian Package Settings 57 | 58 | Various settings for the package are exposed by CPack. In this example we set the 59 | following: 60 | 61 | [source,cmake] 62 | ---- 63 | # Set a Package Maintainer. 64 | # This is required 65 | set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Thom Troy") 66 | 67 | # Set a Package Version 68 | set(CPACK_PACKAGE_VERSION ${deb_example_VERSION}) 69 | ---- 70 | 71 | Which sets the maintainer and version. More debian specific settings are specified below 72 | or at link:https://cmake.org/Wiki/CMake:CPackPackageGenerators#Debian_Generator_specific_settings[the CPack Wiki] 73 | 74 | [cols=",",options="header",] 75 | |======================================================================= 76 | |Variable |Info 77 | |CPACK_DEBIAN_PACKAGE_MAINTAINER |Maintainer information 78 | 79 | |CPACK_PACKAGE_DESCRIPTION_SUMMARY |Package short description 80 | 81 | |CPACK_PACKAGE_DESCRIPTION |Package description 82 | 83 | |CPACK_DEBIAN_PACKAGE_DEPENDS |For advanced users to add custom scripts. 84 | 85 | |CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA |The build directory you are currently in. 86 | 87 | |CPACK_DEBIAN_PACKAGE_SECTION |Package section (see link:http://packages.debian.org/stable/[here]) 88 | 89 | |CPACK_DEBIAN_PACKAGE_VERSION |Package version 90 | |======================================================================= 91 | 92 | # Building the Example 93 | 94 | [source,bash] 95 | ---- 96 | $ mkdir build 97 | 98 | $ cd build/ 99 | 100 | $ cmake .. 101 | -- The C compiler identification is GNU 4.8.4 102 | -- The CXX compiler identification is GNU 4.8.4 103 | -- Check for working C compiler: /usr/bin/cc 104 | -- Check for working C compiler: /usr/bin/cc -- works 105 | -- Detecting C compiler ABI info 106 | -- Detecting C compiler ABI info - done 107 | -- Check for working CXX compiler: /usr/bin/c++ 108 | -- Check for working CXX compiler: /usr/bin/c++ -- works 109 | -- Detecting CXX compiler ABI info 110 | -- Detecting CXX compiler ABI info - done 111 | -- Configuring done 112 | -- Generating done 113 | -- Build files have been written to: /home/matrim/workspace/cmake-examples/06-installer/deb/build 114 | 115 | $ make help 116 | The following are some of the valid targets for this Makefile: 117 | ... all (the default if no target is provided) 118 | ... clean 119 | ... depend 120 | ... cmake_examples_deb 121 | ... cmake_examples_deb_bin 122 | ... edit_cache 123 | ... install 124 | ... install/local 125 | ... install/strip 126 | ... list_install_components 127 | ... package 128 | ... package_source 129 | ... rebuild_cache 130 | ... src/Hello.o 131 | ... src/Hello.i 132 | ... src/Hello.s 133 | ... src/main.o 134 | ... src/main.i 135 | ... src/main.s 136 | 137 | $ make package 138 | Scanning dependencies of target cmake_examples_deb 139 | [ 50%] Building CXX object CMakeFiles/cmake_examples_deb.dir/src/Hello.cpp.o 140 | Linking CXX shared library libcmake_examples_deb.so 141 | [ 50%] Built target cmake_examples_deb 142 | Scanning dependencies of target cmake_examples_deb_bin 143 | [100%] Building CXX object CMakeFiles/cmake_examples_deb_bin.dir/src/main.cpp.o 144 | Linking CXX executable cmake_examples_deb_bin 145 | [100%] Built target cmake_examples_deb_bin 146 | Run CPack packaging tool... 147 | CPack: Create package using DEB 148 | CPack: Install projects 149 | CPack: - Run preinstall target for: cmake_examples_deb 150 | CPack: - Install project: cmake_examples_deb 151 | CPack: Create package 152 | CPack: - package: /home/matrim/workspace/cmake-examples/06-installer/deb/build/cmake_examples_deb-0.2.2-Linux.deb generated. 153 | 154 | $ ls 155 | CMakeCache.txt cmake_examples_deb-0.2.2-Linux.deb cmake_examples_deb_bin CMakeFiles cmake_install.cmake CPackConfig.cmake _CPack_Packages CPackSourceConfig.cmake install_manifest.txt libcmake_examples_deb.so Makefile 156 | 157 | ---- 158 | -------------------------------------------------------------------------------- /06-installer/deb/cmake-examples.conf: -------------------------------------------------------------------------------- 1 | # Sample configuration file that could be installed 2 | -------------------------------------------------------------------------------- /06-installer/deb/include/Hello.h: -------------------------------------------------------------------------------- 1 | #ifndef __HELLO_H__ 2 | #define __HELLO_H__ 3 | 4 | class Hello 5 | { 6 | public: 7 | void print(); 8 | }; 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /06-installer/deb/post_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | make package 4 | -------------------------------------------------------------------------------- /06-installer/deb/src/Hello.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "Hello.h" 4 | 5 | void Hello::print() 6 | { 7 | std::cout << "Hello Install!" << std::endl; 8 | } 9 | -------------------------------------------------------------------------------- /06-installer/deb/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "Hello.h" 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | Hello hi; 6 | hi.print(); 7 | return 0; 8 | } -------------------------------------------------------------------------------- /07-package-management/A-using-system-provide-packages/README.adoc: -------------------------------------------------------------------------------- 1 | = Using System Provided Package Manager 2 | :toc: 3 | :toc-placement!: 4 | 5 | toc::[] 6 | 7 | # Introduction 8 | 9 | Using your system provided packages is one of the oldest and most common form of package management solutions. For this, you use your systems package installer (e.g. apt, yum) to install libraries and headers into common locations. CMake can then use the `find_package()` function to search for these and make them available to your program. 10 | 11 | # Examples 12 | 13 | I have already shown how to do this in the link:https://github.com/ttroy50/cmake-examples/tree/master/01-basic/H-third-party-library[third party library] example from the basic section and the link:https://github.com/ttroy50/cmake-examples/tree/master/05-unit-testing/boost[boost unit test] example. 14 | -------------------------------------------------------------------------------- /07-package-management/B-vendoring-code/README.adoc: -------------------------------------------------------------------------------- 1 | = Vendoring Code 2 | :toc: 3 | :toc-placement!: 4 | 5 | toc::[] 6 | 7 | # Introduction 8 | 9 | Vendoring code means to include the third party code inside your repository and build it as part of your project. It is a way to ensure that all files required to build your project are part of the development environment. 10 | 11 | # Implementation 12 | 13 | ## Including 3rd Party Code 14 | 15 | Typically, this might take the form or a `3rd_party` or `vendor` directory, in which you copy the source of the libraries you want to include. For example, you may do something like: 16 | 17 | ``` 18 | $ tree 19 | . 20 | ├── 3rd_party 21 | │   └── catch2 22 | │   ├── catch2 23 | │   │   └── catch.hpp 24 | │   └── CMakeLists.txt 25 | ├── CMakeLists.txt 26 | ├── src 27 | │   └── example.cpp 28 | ``` 29 | 30 | 31 | If these projects support CMake directly, it may be possible to do `add_subdirectory()` on the libraries folder and have that project build and be made available to your code. 32 | 33 | If the third party code doesn't support CMake, you may need to create a "shim" layer on top of the project to allow it to be build and discovered from CMake. 34 | 35 | ## Using git to vendor code 36 | 37 | A slightly different method to include the third party code can be to use your SCM software to manage the process for you. 38 | 39 | In the case of git, you can use link:https://git-scm.com/book/en/v2/Git-Tools-Submodules[git sub-modules] or link:https://git-scm.com/book/en/v1/Git-Tools-Subtree-Merging[git subtree]. These can pull the correct version of the third party code into your repository on initialisation / update. 40 | 41 | # Examples 42 | 43 | A simple example of vendoring code can already be seen in the link:https://github.com/ttroy50/cmake-examples/tree/master/05-unit-testing/catch2-vendored[catch2] testing tutorial. 44 | -------------------------------------------------------------------------------- /07-package-management/C-external-project-add/README.adoc: -------------------------------------------------------------------------------- 1 | = External Project 2 | :toc: 3 | :toc-placement!: 4 | 5 | toc::[] 6 | 7 | # Introduction 8 | 9 | CMake supports downloading and building an external project using the link:https://cmake.org/cmake/help/latest/module/ExternalProject.html[External Project] commands. By adding +ExternalProject_Add+ to your code you can have CMake automatically download a source file from either HTTP or a source control system (e.g. git). 10 | 11 | Once configured an external project will generate a custom target which can be used to control the download, update, build, test, and install phases of the external project. 12 | 13 | # Implementation 14 | 15 | ## Standard 16 | 17 | A simple example of an external project is as follows: 18 | 19 | [source,cmake] 20 | ---- 21 | include(ExternalProject) 22 | ExternalProject_Add(googletest 23 | URL https://github.com/google/googletest/archive/bfc0ffc8a698072c794ae7299db9cb6866f4c0bc.tar.gz_ 24 | ) 25 | ---- 26 | 27 | Once added you will have a target `googletest` which will attempt to download, build, and install google test when your build your project. 28 | 29 | [NOTE] 30 | ==== 31 | This will attempt to install google test to your standard locations e.g. `/usr/` and may fail if you are not root. To skip the install step you can add a line `INSTALL_COMMAND ""` 32 | ==== 33 | 34 | By default the project is assumed to work via CMake and external project will know how to build using standard CMake commands. If the external project uses a different build system, you can set the various commands using +INSTALL_COMMAND+, +CONFIGURE_COMMAND+, +BUILD_COMMAND+, etc. 35 | 36 | ## Alternative 37 | 38 | An alternative method to install packages is to have the ExternalProject command run at CMake configure time. This can cause the download to happen at the configure step and you may then use +add_subdirectory+ to add the project to your code (assuming it uses CMake). An example of this can be found in the link:https://github.com/ttroy50/cmake-examples/tree/master/05-unit-testing/google-test-download[google-test-download] tutorial. 39 | 40 | A more generic version of the download code can be found link:https://github.com/Crascit/DownloadProject[here]. -------------------------------------------------------------------------------- /07-package-management/D-conan/README.adoc: -------------------------------------------------------------------------------- 1 | = Conan 2 | :toc: 3 | :toc-placement!: 4 | 5 | toc::[] 6 | 7 | # Introduction 8 | 9 | link:https://conan.io[Conan] is an open source, decentralized, and multi-platform package manager that can be used to create and share native libraries and binaries. It supports multiple build systems (CMake, Visual Studio, Makefiles) and OSes (Linux, Windows, and Mac). 10 | 11 | Conan servers can be installed privately or you can use public servers and packages made available by link:https://bintray.com/conan/conan-center[Jfrog bintray]. 12 | 13 | Full documentation for conan can be found from link:https://docs.conan.io/en/latest/[here] 14 | 15 | # Installing Conan 16 | 17 | Conan is a python application and can be installed using pip. 18 | 19 | [source,bash] 20 | ---- 21 | $ sudo apt-get install python3 python3-pip 22 | $ pip3 install conan 23 | $ conan help 24 | Consumer commands 25 | install Installs the requirements specified in a recipe (conanfile.py or conanfile.txt). 26 | ... 27 | ---- 28 | 29 | Alternatively, native packages are available for most operating systems. Full details are available link:https://docs.conan.io/en/latest/installation.html[here]. 30 | 31 | # Conan Profile 32 | 33 | In conan link:https://docs.conan.io/en/latest/reference/profiles.html#profiles[profiles] control information such as the compiler and environments that are available on your system. 34 | 35 | To create a new default profile run 36 | 37 | [source,bash] 38 | ---- 39 | $ conan profile new default --detect 40 | Found gcc 5.4 41 | gcc>=5, using the major as version 42 | Profile created with detected settings: /home/devuser/.conan/profiles/default 43 | ---- 44 | 45 | The generated profile will look something like: 46 | 47 | [source,bash] 48 | ---- 49 | [settings] 50 | os=Linux 51 | os_build=Linux 52 | arch=x86_64 53 | arch_build=x86_64 54 | compiler=gcc 55 | compiler.version=5 56 | compiler.libcxx=libstdc++ 57 | build_type=Release 58 | [options] 59 | [build_requires] 60 | [env] 61 | ---- 62 | 63 | 64 | [NOTE] 65 | ==== 66 | If you are using GCC compiler >= 5.1, Conan will set the compiler.libcxx to the old ABI for backwards compatibility. You can change this with the following commands: 67 | 68 | [source,bash] 69 | ---- 70 | $ conan profile update settings.compiler.libcxx=libstdc++11 default 71 | ---- 72 | 73 | [source,bash] 74 | ---- 75 | [settings] 76 | os=Linux 77 | os_build=Linux 78 | arch=x86_64 79 | arch_build=x86_64 80 | compiler=gcc 81 | compiler.version=5 82 | compiler.libcxx=libstdc++11 83 | build_type=Release 84 | [options] 85 | [build_requires] 86 | [env] 87 | ---- 88 | 89 | You can find more information about this link:https://docs.conan.io/en/latest/howtos/manage_gcc_abi.html#manage-gcc-abi[here]. 90 | ==== 91 | 92 | All examples provided will assume that the ABI being used for libstdc++ is the Cpp11 ABI. 93 | 94 | # Finding Packages 95 | 96 | Remote repositories can be searched for conan packages. By default the `conan-center` remote is configured. This is located in link:https://bintray.com/conan/conan-center[bintray]. 97 | 98 | ## Searching for Packages 99 | 100 | You can search for packages using the `conan search` command. For example, to search for a package such as link:https://github.com/fmtlib/fmt[fmtlib] you can run: 101 | 102 | [source,bash] 103 | ---- 104 | $ conan search fmt* --remote=conan-center 105 | Existing package recipes: 106 | 107 | fmt/4.0.0@bincrafters/stable 108 | fmt/4.1.0@bincrafters/stable 109 | fmt/5.0.0@bincrafters/stable 110 | fmt/5.1.0@bincrafters/stable 111 | fmt/5.2.0@bincrafters/stable 112 | fmt/5.2.1@bincrafters/stable 113 | fmt/5.3.0@bincrafters/stable 114 | 115 | ---- 116 | 117 | ## Inspecting Packages 118 | 119 | You can then inspect a package using the `conan inspect` command. To inspect one one of the fmt packages from the search command above you can run: 120 | 121 | [source,bash] 122 | ---- 123 | $ conan inspect fmt/5.3.0@bincrafters/stable --remote=conan-center 124 | name: fmt 125 | version: 5.3.0 126 | url: https://github.com/bincrafters/conan-fmt 127 | homepage: https://github.com/fmtlib/fmt 128 | license: MIT 129 | author: Bincrafters 130 | description: A safe and fast alternative to printf and IOStreams. 131 | topics: None 132 | generators: cmake 133 | exports: ['LICENSE.md'] 134 | exports_sources: ['CMakeLists.txt'] 135 | short_paths: False 136 | apply_env: True 137 | build_policy: None 138 | revision_mode: hash 139 | settings: ('os', 'compiler', 'build_type', 'arch') 140 | options: 141 | fPIC: [True, False] 142 | header_only: [True, False] 143 | shared: [True, False] 144 | with_fmt_alias: [True, False] 145 | default_options: 146 | fPIC: True 147 | header_only: False 148 | shared: False 149 | with_fmt_alias: False 150 | ---- 151 | 152 | This shows details about the package including what link:https://docs.conan.io/en/latest/using_packages/conanfile_txt.html#options[options] can be set when including the package. In the case of fmtlib there are 4 options which allow you to specify the type of installion you want. 153 | 154 | # Examples 155 | 156 | The examples included are: 157 | 158 | - link:i-basic[Basic]. A basic example linking against one library. 159 | - link:ii-basic-targets[Using Targets]. The basic example, except using modern CMake targets. 160 | -------------------------------------------------------------------------------- /07-package-management/D-conan/i-basic/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project (conan_third_party_include) 3 | 4 | set(CMAKE_CXX_STANDARD 11) 5 | 6 | # Included the conan build information 7 | include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) 8 | conan_basic_setup() 9 | 10 | # Add an executable 11 | add_executable(third_party_include main.cpp) 12 | 13 | # link against the fmt target supplied by conan 14 | target_link_libraries(third_party_include 15 | PRIVATE 16 | ${CONAN_LIBS} 17 | ) -------------------------------------------------------------------------------- /07-package-management/D-conan/i-basic/conanfile.txt: -------------------------------------------------------------------------------- 1 | [requires] 2 | fmt/5.3.0@bincrafters/stable 3 | 4 | [generators] 5 | cmake 6 | -------------------------------------------------------------------------------- /07-package-management/D-conan/i-basic/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | fmt::print("Hello, {}. This is {}!\n", "conan", "fmtlib"); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /07-package-management/D-conan/i-basic/run_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | conan_bin=`which conan` 4 | 5 | if [ -z $conan_bin ]; then 6 | exit 0 7 | fi 8 | 9 | conan profile show default || { 10 | conan profile new default --detect 11 | } 12 | conan profile update settings.compiler.libcxx=libstdc++11 default 13 | 14 | echo "correct version of cmake" 15 | mkdir -p build && cd build && conan install .. && cmake .. && make 16 | if [ $? -ne 0 ]; then 17 | echo "Error running example" 18 | exit 1 19 | fi 20 | -------------------------------------------------------------------------------- /07-package-management/D-conan/ii-basic-targets/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project (conan_third_party_include) 3 | 4 | set(CMAKE_CXX_STANDARD 11) 5 | 6 | # Included the conan build information 7 | include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) 8 | conan_basic_setup(TARGETS) 9 | 10 | # Add an executable 11 | add_executable(third_party_include main.cpp) 12 | 13 | # link against the fmt target supplied by conan 14 | target_link_libraries(third_party_include 15 | PRIVATE 16 | CONAN_PKG::fmt 17 | ) 18 | -------------------------------------------------------------------------------- /07-package-management/D-conan/ii-basic-targets/conanfile.txt: -------------------------------------------------------------------------------- 1 | [requires] 2 | fmt/5.3.0@bincrafters/stable 3 | 4 | [generators] 5 | cmake 6 | -------------------------------------------------------------------------------- /07-package-management/D-conan/ii-basic-targets/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | fmt::print("Hello, {}. This is {}!\n", "conan", "fmtlib"); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /07-package-management/D-conan/ii-basic-targets/run_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | conan_bin=`which conan` 4 | 5 | if [ -z $conan_bin ]; then 6 | exit 0 7 | fi 8 | 9 | conan profile show default || { 10 | conan profile new default --detect 11 | } 12 | conan profile update settings.compiler.libcxx=libstdc++11 default 13 | 14 | echo "correct version of cmake" 15 | mkdir -p build && cd build && conan install .. && cmake .. && make 16 | if [ $? -ne 0 ]; then 17 | echo "Error running example" 18 | exit 1 19 | fi 20 | -------------------------------------------------------------------------------- /07-package-management/README.adoc: -------------------------------------------------------------------------------- 1 | = Package Management 2 | :toc: 3 | :toc-placement!: 4 | 5 | toc::[] 6 | 7 | [[intro]] 8 | Introduction 9 | ------------ 10 | 11 | For C++ and CMake there is currently no universally accepted way of managing and packaging dependencies. However, in recent years there have been some new and interesting package management systems made available. While these are separate systems to CMake, most of them have are designed to integrate directly into a CMake based build system. 12 | 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Thom Troy 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 | 23 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | 2 | = CMake Examples 3 | :toc: 4 | :toc-placement!: 5 | 6 | toc::[] 7 | 8 | # Introduction 9 | 10 | https://cmake.org/[CMake] is a cross-platform open-source meta-build system which 11 | can build, test and package software. It can be used to support multiple native build environments including 12 | make, Apple's xcode and Microsoft Visual Studio. 13 | 14 | This repository includes some example modern CMake configurations which I have picked up 15 | when exploring it's usage for various projects. The examples are laid out in a tutorial like format. 16 | The first examples are very basic and slowly increase in complexity drawing on previous examples to show 17 | more complex use cases. 18 | 19 | These examples have been tested on Ubuntu 16.04 but should work under any Linux system that supports CMake v3.5+. 20 | 21 | This branch works with the CMake version 3.5 onwards. 22 | 23 | * For examples that use CMake version 2.x see the branch link:https://github.com/ttroy50/cmake-examples/tree/v2-style-includes[v2-style-includes]. 24 | * For examples that use CMake version 3.0 see the branch link:https://github.com/ttroy50/cmake-examples/tree/v3.0-minimum[v3.0-minimum] 25 | 26 | image:https://travis-ci.org/ttroy50/cmake-examples.svg?branch=master["Build Status", link="https://travis-ci.org/ttroy50/cmake-examples"] 27 | 28 | # Requirements 29 | 30 | The basic requirements for most examples are: 31 | 32 | * CMake v3.5+ 33 | * A c++ compiler (defaults to gcc) 34 | * make 35 | 36 | ## Installation on Ubuntu 37 | 38 | The easiest way to install the above on Ubuntu is as follows 39 | 40 | [source,bash] 41 | ---- 42 | $ sudo apt-get install build-essential 43 | $ sudo apt-get install cmake 44 | ---- 45 | 46 | Some specific examples may require other tools including: 47 | 48 | * http://www.boost.org/[boost] 49 | 50 | $ sudo apt-get install libboost-all-dev 51 | 52 | * https://github.com/google/protobuf[protobuf] 53 | 54 | $ sudo apt-get install libprotobuf-dev 55 | $ sudo apt-get install protobuf-compiler 56 | 57 | * http://cppcheck.sourceforge.net/[cppcheck] 58 | 59 | $ sudo apt-get install cppcheck 60 | 61 | * http://clang.llvm.org/[clang] 62 | 63 | $ sudo apt-get install clang-3.6 64 | 65 | * https://ninja-build.org/[ninja] 66 | 67 | $ sudo apt-get install ninja-build 68 | 69 | * link:https://conan.io[conan] 70 | 71 | $ sudo apt-get install python3 python3-pip 72 | $ sudo pip3 install conan 73 | 74 | ## Docker 75 | 76 | Docker containers with all requirements and various versions of CMake are generated to help make testing the examples easier. These are available from the docker hub repository link:https://hub.docker.com/r/matrim/cmake-examples/[matrim/cmake-examples]. 77 | 78 | To build the full set of cmake-examples test cases you can run: 79 | 80 | [source,bash] 81 | ---- 82 | docker run -it matrim/cmake-examples:3.5.1 83 | cd ~ 84 | git clone https://github.com/ttroy50/cmake-examples.git code 85 | cd code 86 | ./test.sh 87 | ---- 88 | 89 | For more details on build and running the docker containers link:here[dockerfiles]. 90 | 91 | # Other Links 92 | 93 | There are many CMake tutorials and examples online. The list below includes links 94 | to some of these which I have found helpful in my CMake journey. 95 | 96 | * https://web.archive.org/web/20160314094326/https://www.kdab.com/~stephen/moderncmake.pdf[Modern CMake Slides] 97 | * https://rix0r.nl/blog/2015/08/13/cmake-guide/[rix0r Modern CMake Blog] 98 | * https://cmake.org/cmake-tutorial/[Official CMake Tutorial] 99 | * https://gitlab.kitware.com/cmake/community/wikis/home[Official CMake Wiki] 100 | * https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/Useful-Variables[CMake Useful Variables] 101 | * http://derekmolloy.ie/hello-world-introductions-to-cmake/[Derek Molloy - Intro to CMake] 102 | * http://techminded.net/blog/modular-c-projects-with-cmake.html[Modular C++ Projects] 103 | * https://web.archive.org/web/20190320121339/http://voices.canonical.com/jussi.pakkanen/2013/03/26/a-list-of-common-cmake-antipatterns/[Common CMake Anti-Patterns] 104 | * http://baptiste-wicht.com/posts/2014/04/install-use-clang-static-analyzer-cmake.html[Using clang static analyser with CMake] 105 | * https://cmake.org/pipermail/cmake/2011-April/043709.html[Static Analysis with CDash] - Includes some info about using CppCheck with CMake 106 | * https://samthursfield.wordpress.com/2015/10/20/some-cmake-tips/[CMake Tips] 107 | * https://www.johnlamp.net/cmake-tutorial.html[John Lamp - CMake Tutorial] 108 | * link:https://docs.conan.io[Conan Documentation] 109 | -------------------------------------------------------------------------------- /cmake-examples.sublime-project: -------------------------------------------------------------------------------- 1 | { 2 | "folders": 3 | [ 4 | { 5 | "path": "." 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /dockerfiles/README.adoc: -------------------------------------------------------------------------------- 1 | 2 | = CMake Examples with Docker 3 | :toc: 4 | :toc-placement!: 5 | 6 | toc::[] 7 | 8 | # Docker 9 | 10 | https://www.docker.com/[Docker] allows you to package software in a container which contains a filesystem with all dependencies. This allows having containers which include everything needed to run and test our examples. And as a result of packaging all dependencies we can create containers to include different versions of cmake so that it is possible to easily make sure our examples work for many cmake versions. 11 | 12 | # Building 13 | 14 | To build a container from the this directory run the following: 15 | 16 | [source,bash] 17 | ---- 18 | $ docker build --rm -f -t . 19 | ---- 20 | 21 | For example: 22 | 23 | [source,bash] 24 | ---- 25 | $ docker build --rm -f ubuntu14.04-cmake-3.5.1 -t matrim/cmake-examples:3.5.1 . 26 | ---- 27 | 28 | In this example the tag is created as follows 29 | 30 | /: 31 | 32 | This will tag the container as belong to my repository with the label of the container being the version of cmake installed. 33 | 34 | ## Pre-build Images 35 | 36 | I have pre-build images and pushed them to the https://hub.docker.com[docker hub] in the repository https://hub.docker.com/r/matrim/cmake-examples/[matrim/cmake-examples]. 37 | 38 | The current usable images include the following versions of cmake: 39 | 40 | * Ubuntu 16.04 with CMake 3.5.1 41 | 42 | $ docker pull docker pull matrim/cmake-examples:3.5.1 43 | 44 | * Ubuntu 16.04 with CMake 3.10.3 45 | 46 | $ docker pull docker pull matrim/cmake-examples:3.10.3 47 | 48 | Some old images which work with older version of the repository include: 49 | 50 | * Ubuntu 14.04 with CMake 2.8.12.2 51 | 52 | $ docker pull docker pull matrim/cmake-examples:2.8.12.2 53 | 54 | * Ubuntu 14.04 with CMake 3.4.3 55 | 56 | $ docker pull docker pull matrim/cmake-examples:3.4.3 57 | 58 | # Running 59 | 60 | When run the images will automatically create a non root user called devuser, with a default command to launch a bash shell in the users home directory. 61 | 62 | If you want to set the UID and GID for this user you can pass them in via the environment variables `DEV_UID` and `DEV_GID` 63 | 64 | For example 65 | 66 | [source,bash] 67 | ---- 68 | docker run -e DEV_UID=`id -u` -e DEV_GID=`id -u` -it matrim/cmake-examples:3.5.1 69 | ---- 70 | 71 | 72 | To build the full set of cmake-examples test cases you can run: 73 | 74 | [source,bash] 75 | ---- 76 | docker run -it matrim/cmake-examples:3.5.1 77 | git clone https://github.com/ttroy50/cmake-examples.git 78 | cd cmake-examples 79 | ./test.sh 80 | ---- 81 | 82 | 83 | If you already have a checkout of the cmake-examples you can load the directory as a docker volume. 84 | 85 | Below is an example of loading a volume and automatically running all cmake-example test cases: 86 | 87 | [source,bash] 88 | ---- 89 | docker run --rm -e DEV_UID=`id -u` -e DEV_GID=`id -u` -v /checkout/directory:/data/code -it matrim/cmake-examples:3.5.1 /data/code/test.sh 90 | ---- 91 | -------------------------------------------------------------------------------- /dockerfiles/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Setup script for the cmake-examples repository 3 | # Will create a non root user using the UID and GID passed in from environment 4 | # variables and give them sudo access 5 | # 6 | ret=false 7 | output=`getent passwd devuser 2>&1` 8 | result=$? 9 | if [ $result -ne 0 ] ; then 10 | echo "Creating devuser" 11 | if [ -z $DEV_UID ]; then 12 | DEV_UID=1000 13 | fi 14 | 15 | if [ -z $DEV_GID ]; then 16 | DEV_GID=1000 17 | fi 18 | 19 | groupadd -g $DEV_GID devgroup 20 | useradd -c 'container user' -u $DEV_UID -g $DEV_GID -d /home/devuser -m devuser 21 | echo "devuser:todo_$DEV_UID_$DEV_GID" | chpasswd 22 | sudo adduser devuser sudo 23 | echo "%sudo ALL=NOPASSWD: ALL" >> /etc/sudoers 24 | fi 25 | 26 | exec gosu devuser "$@" 27 | -------------------------------------------------------------------------------- /dockerfiles/ubuntu14.04-cmake-3.4.3: -------------------------------------------------------------------------------- 1 | # Container for building and testing cmake-examples with cmake v3.4.3 2 | FROM ubuntu:14.04 3 | MAINTAINER Thom Troy 4 | 5 | RUN apt-get update && apt-get install -y build-essential \ 6 | sudo \ 7 | libboost-all-dev \ 8 | libprotobuf-dev \ 9 | protobuf-compiler \ 10 | clang-3.6 \ 11 | clang-format-3.6 \ 12 | ninja-build \ 13 | wget \ 14 | git \ 15 | && apt-get clean \ 16 | && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \ 17 | && apt-get autoremove -y 18 | 19 | RUN cd /usr/local/src \ 20 | && wget https://github.com/tianon/gosu/releases/download/1.10/gosu-amd64 \ 21 | && mv gosu-amd64 /usr/local/bin/gosu \ 22 | && chmod +x /usr/local/bin/gosu 23 | 24 | ADD setup.sh /setup.sh 25 | RUN chmod +x /setup.sh 26 | 27 | RUN cd /usr/local/src \ 28 | && wget https://cmake.org/files/v3.4/cmake-3.4.3.tar.gz \ 29 | && tar xvf cmake-3.4.3.tar.gz \ 30 | && cd cmake-3.4.3 \ 31 | && ./bootstrap \ 32 | && make \ 33 | && make install \ 34 | && cd .. \ 35 | && rm -rf cmake* 36 | 37 | # cppcheck 38 | RUN cd /usr/local/src \ 39 | && wget https://github.com/danmar/cppcheck/archive/1.79.tar.gz \ 40 | && tar xvf 1.79.tar.gz \ 41 | && cd cppcheck-1.79 \ 42 | && mkdir build \ 43 | && cd build \ 44 | && cmake .. \ 45 | && make install \ 46 | && cd ../.. && rm -rf cppcheck* 47 | 48 | 49 | CMD ["/bin/bash"] 50 | 51 | ENTRYPOINT ["/setup.sh"] 52 | -------------------------------------------------------------------------------- /dockerfiles/ubuntu14.04-default-2.8.12.2: -------------------------------------------------------------------------------- 1 | # Container for building and testing cmake-examples with default cmake v2.8.12.2 2 | FROM ubuntu:14.04 3 | MAINTAINER Thom Troy 4 | 5 | RUN apt-get update && apt-get install -y build-essential \ 6 | sudo \ 7 | cmake \ 8 | libboost-all-dev \ 9 | libprotobuf-dev \ 10 | protobuf-compiler \ 11 | cppcheck \ 12 | clang-3.6 \ 13 | clang-format-3.6 \ 14 | ninja-build \ 15 | wget \ 16 | git \ 17 | && apt-get clean \ 18 | && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 19 | 20 | # tini required to handle issue with building deb packages from cmake v2.8 21 | RUN cd /usr/local/src \ 22 | && wget https://github.com/krallin/tini/archive/v0.9.0.tar.gz \ 23 | && tar xvf v0.9.0.tar.gz \ 24 | && cd tini-0.9.0 \ 25 | && cmake . \ 26 | && make \ 27 | && make install \ 28 | && cd /usr/local/src \ 29 | && rm -rf tini-* \ 30 | && rm -rf v0.9.0.tar.gz 31 | 32 | RUN cd /usr/local/src \ 33 | && wget https://github.com/tianon/gosu/releases/download/1.10/gosu-amd64 \ 34 | && mv gosu-amd64 /usr/local/bin/gosu \ 35 | && chmod +x /usr/local/bin/gosu 36 | 37 | ADD setup.sh /setup.sh 38 | RUN chmod +x /setup.sh 39 | 40 | CMD ["/bin/bash"] 41 | ENTRYPOINT ["/usr/local/bin/tini", "--", "/setup.sh"] 42 | -------------------------------------------------------------------------------- /dockerfiles/ubuntu16.04-cmake-3.10.3: -------------------------------------------------------------------------------- 1 | # Container for building and testing cmake-examples with CMake 3.10.3 2 | FROM ubuntu:16.04 3 | MAINTAINER Thom Troy 4 | 5 | RUN apt-get update && apt-get install -y build-essential \ 6 | sudo \ 7 | cmake \ 8 | libboost-all-dev \ 9 | libprotobuf-dev \ 10 | protobuf-compiler \ 11 | clang-3.6 \ 12 | clang-format-3.6 \ 13 | ninja-build \ 14 | wget \ 15 | git \ 16 | python3 \ 17 | python3-pip \ 18 | && pip3 install conan \ 19 | && apt-get clean \ 20 | && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 21 | 22 | RUN cd /usr/local/src \ 23 | && wget https://cmake.org/files/v3.10/cmake-3.10.3.tar.gz \ 24 | && tar xvf cmake-3.10.3.tar.gz \ 25 | && cd cmake-3.10.3 \ 26 | && ./bootstrap \ 27 | && make \ 28 | && make install \ 29 | && cd .. \ 30 | && rm -rf cmake* 31 | 32 | # cppcheck 33 | RUN cd /usr/local/src \ 34 | && wget https://github.com/danmar/cppcheck/archive/1.79.tar.gz \ 35 | && tar xvf 1.79.tar.gz \ 36 | && cd cppcheck-1.79 \ 37 | && mkdir build \ 38 | && cd build \ 39 | && cmake .. \ 40 | && make install \ 41 | && cd ../.. && rm -rf cppcheck* 42 | 43 | RUN cd /usr/local/src \ 44 | && wget https://github.com/tianon/gosu/releases/download/1.10/gosu-amd64 \ 45 | && mv gosu-amd64 /usr/local/bin/gosu \ 46 | && chmod +x /usr/local/bin/gosu 47 | 48 | ADD setup.sh /setup.sh 49 | RUN chmod +x /setup.sh 50 | 51 | CMD ["/bin/bash"] 52 | ENTRYPOINT ["/setup.sh"] 53 | -------------------------------------------------------------------------------- /dockerfiles/ubuntu16.04-default-cmake-3.5.1: -------------------------------------------------------------------------------- 1 | # Container for building and testing cmake-examples with default cmake v3.5.1 2 | FROM ubuntu:16.04 3 | MAINTAINER Thom Troy 4 | 5 | RUN apt-get update && apt-get install -y build-essential \ 6 | sudo \ 7 | cmake \ 8 | libboost-all-dev \ 9 | libprotobuf-dev \ 10 | protobuf-compiler \ 11 | clang-3.6 \ 12 | clang-format-3.6 \ 13 | ninja-build \ 14 | wget \ 15 | git \ 16 | python3 \ 17 | python3-pip \ 18 | && pip3 install conan \ 19 | && apt-get clean \ 20 | && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 21 | 22 | # cppcheck 23 | RUN cd /usr/local/src \ 24 | && wget https://github.com/danmar/cppcheck/archive/1.79.tar.gz \ 25 | && tar xvf 1.79.tar.gz \ 26 | && cd cppcheck-1.79 \ 27 | && mkdir build \ 28 | && cd build \ 29 | && cmake .. \ 30 | && make install \ 31 | && cd ../.. && rm -rf cppcheck* 32 | 33 | RUN cd /usr/local/src \ 34 | && wget https://github.com/tianon/gosu/releases/download/1.10/gosu-amd64 \ 35 | && mv gosu-amd64 /usr/local/bin/gosu \ 36 | && chmod +x /usr/local/bin/gosu 37 | 38 | ADD setup.sh /setup.sh 39 | RUN chmod +x /setup.sh 40 | 41 | CMD ["/bin/bash"] 42 | ENTRYPOINT ["/setup.sh"] 43 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # print out cmake information to help with debugging. 4 | 5 | cmake --version 6 | cmake --help 7 | 8 | # Find the directory this test script is in and then run them from there 9 | EXAMPLES_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 10 | echo "running examples in $EXAMPLES_DIR" 11 | 12 | cd $EXAMPLES_DIR 13 | 14 | dirs=(./01-basic/A-hello-cmake \ 15 | ./01-basic/B-hello-headers \ 16 | ./01-basic/C-static-library \ 17 | ./01-basic/D-shared-library \ 18 | ./01-basic/E-installing \ 19 | ./01-basic/F-build-type \ 20 | ./01-basic/G-compile-flags \ 21 | ./01-basic/H-third-party-library \ 22 | ./01-basic/I-compiling-with-clang \ 23 | ./01-basic/J-building-with-ninja \ 24 | ./01-basic/K-imported-targets \ 25 | ./01-basic/L-cpp-standard/i-common-method \ 26 | ./01-basic/L-cpp-standard/ii-cxx-standard \ 27 | ./01-basic/L-cpp-standard/iii-compile-features \ 28 | ./02-sub-projects/A-basic \ 29 | ./03-code-generation/protobuf \ 30 | ./03-code-generation/configure-files \ 31 | ./04-static-analysis/cppcheck \ 32 | ./04-static-analysis/cppcheck-compile-commands \ 33 | ./04-static-analysis/clang-analyzer \ 34 | ./04-static-analysis/clang-format \ 35 | ./05-unit-testing/boost \ 36 | ./05-unit-testing/google-test-download \ 37 | ./05-unit-testing/catch2-vendored \ 38 | ./06-installer/deb \ 39 | ./07-package-management/D-conan/i-basic \ 40 | ./07-package-management/D-conan/ii-basic-targets \ 41 | ) 42 | 43 | ROOT_DIR=`pwd` 44 | 45 | for dir in ${dirs[*]} 46 | do 47 | echo "" 48 | echo "" 49 | echo "Running test for $dir" 50 | cd $ROOT_DIR 51 | if [ -d "$ROOT_DIR/$dir/build" ]; then 52 | echo "deleting $dir/build" 53 | rm -r $dir/build 54 | fi 55 | 56 | if [ -f "$dir/pre_test.sh" ]; then 57 | echo "running pre test" 58 | $ROOT_DIR/$dir/pre_test.sh 59 | if [ $? -ne 0 ]; then 60 | echo "Error running pre_test for $dir" 61 | exit 1 62 | fi 63 | fi 64 | 65 | if [ -f "$dir/run_test.sh" ]; then 66 | echo "running run_test" 67 | cd $dir && $ROOT_DIR/$dir/run_test.sh 68 | if [ $? -ne 0 ]; then 69 | echo "Error running run_test for $dir" 70 | exit 1 71 | fi 72 | else 73 | cd $dir && mkdir -p build && cd build && cmake .. && make 74 | if [ $? -ne 0 ]; then 75 | echo "Error running example $dir" 76 | exit 1 77 | fi 78 | fi 79 | 80 | if [ -f "$ROOT_DIR/$dir/post_test.sh" ]; then 81 | echo "running post test" 82 | $ROOT_DIR/$dir/post_test.sh 83 | if [ $? -ne 0 ]; then 84 | echo "Error running post_test for $dir" 85 | exit 1 86 | fi 87 | fi 88 | done 89 | 90 | echo "" 91 | echo "" 92 | echo "All Tests Completed" 93 | --------------------------------------------------------------------------------