├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── cmake ├── CMakeRegistry.cmake ├── Config.cmake.in ├── LibraryConfig.cmake ├── SetEnv.cmake └── Uninstall.cmake.in ├── example_external ├── CMakeLists.txt └── bar.cpp ├── example_internal ├── CMakeLists.txt └── bar.cpp ├── foo ├── CMakeLists.txt ├── foo.cpp ├── foo.h └── version.h.in └── scripts ├── build_example_external.sh ├── build_linux.sh ├── build_ninja.sh └── build_win.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # builds 2 | build*/* 3 | _build/ 4 | _install/ 5 | 6 | # kdevelop 7 | *.kdev4 8 | 9 | # Compiled Object files 10 | *.slo 11 | *.lo 12 | *.o 13 | *.obj 14 | 15 | # Compiled Dynamic libraries 16 | *.so 17 | *.dylib 18 | *.dll 19 | 20 | # Compiled Static libraries 21 | *.lai 22 | *.la 23 | *.a 24 | *.lib 25 | 26 | # Executables 27 | *.exe 28 | *.out 29 | *.app 30 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Set minimum version of CMake. 2 | cmake_minimum_required(VERSION 3.9) 3 | 4 | # Set project name and version 5 | project(Foo VERSION 1.2.3) 6 | 7 | # Set environment variables 8 | include(${PROJECT_SOURCE_DIR}/cmake/SetEnv.cmake) 9 | 10 | # Library sources 11 | add_subdirectory(${LIBRARY_FOLDER}) 12 | 13 | # Library examples 14 | add_subdirectory(example_internal) 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Pablo Speciale 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | cmake-example-library 2 | ===================== 3 | 4 | CMake library example that can be found using `find_package()`. 5 | 6 | **Update:** now using modern cmake (version >= 3.9), since commit [46f0b93](https://github.com/pablospe/cmake-example-library/commit/46f0b93e9725588d344f9b3231c6da77ea11a1bc). 7 | 8 | 9 | ### Features 10 | 11 | * The main **advantage** of this example is that it is _auto-generated_. 12 | You only need to change the _project name_, and add the files that need to 13 | be compiled in [foo/CMakeLists.txt](foo/CMakeLists.txt). 14 | 15 | * Autogenetared library version file: `#include ` 16 | 17 | * `FOO_DEBUG` added on Debug. See [foo/foo.cpp#L7-L11](foo/foo.cpp#L7-L11). 18 | 19 | * `CMAKE_DEBUG_POSTFIX = 'd'` (allowing `Debug` and `Release` to not collide). 20 | See [cmake/SetEnv.cmake#L17](cmake/SetEnv.cmake#L17). 21 | 22 | * Static library as default (`BUILD_SHARED_LIBS=OFF`). 23 | See [cmake/SetEnv.cmake#L19-L21](cmake/SetEnv.cmake#L19-L21). 24 | 25 | * `cmake-gui` shows possible options for `CMAKE_BUILD_TYPE` (Release, Debug, 26 | etc.). For _multi-config_ generator, `CMAKE_CONFIGURATION_TYPES` is set 27 | instead of `CMAKE_BUILD_TYPE`. 28 | See [cmake/SetEnv.cmake#L23-L48](cmake/SetEnv.cmake#L23-L48). 29 | 30 | * `Uninstall` target. 31 | See [cmake/SetEnv.cmake#L104-L109](cmake/SetEnv.cmake#L104-L109). 32 | 33 | * Always full RPATH (for shared libraries). 34 | See [cmake/SetEnv.cmake#L111-L132](cmake/SetEnv.cmake#L111-L132). 35 | 36 | * CMake Registry: export package to CMake registry such that it can be easily found by CMake even if it has not been installed to a standard directory. See [cmake/SetEnv.cmake#L135](cmake/SetEnv.cmake#L135). 37 | Possible options: 38 | ``` 39 | -DCMAKE_REGISTRY_FOLDER="OFF" (disable CMake registry [default]) 40 | -DCMAKE_REGISTRY_FOLDER="INSTALL_FOLDER" 41 | -DCMAKE_REGISTRY_FOLDER="BUILD_FOLDER" 42 | ``` 43 | 44 | 45 | ### Usage 46 | 47 | In this example, `Foo` is the library and `Bar` a binary (which uses the library). 48 | 49 | 50 | find_package(Foo REQUIRED) 51 | target_link_libraries(... Foo::foo) 52 | 53 | See [more details](https://github.com/pablospe/cmake-example-library/tree/moderm_cmake#how-to-use-the-library-as-dependency-in-an-external-project) below. 54 | 55 | 56 | ### How to compile? 57 | 58 | Assume the following settings: 59 | 60 | project(Foo) 61 | ... 62 | set(LIBRARY_NAME foo) # [optional] generated automatically (in lowercase) 63 | set(LIBRARY_FOLDER foo) # [optional] generated automatically (in lowercase) 64 | 65 | Example of a local installation: 66 | 67 | > mkdir _build && cd _build 68 | > cmake -DCMAKE_INSTALL_PREFIX=../_install .. 69 | > cmake --build . --target install -j 8 70 | (equivalent to 'make install -j8' in linux) 71 | 72 | Installed files: 73 | 74 | > tree ../_install 75 | 76 | ├── bin 77 | │   └── bar 78 | ├── include 79 | │   └── foo 80 | │   ├── foo.h 81 | │   └── version.h 82 | └── lib 83 | ├── cmake 84 | │   └── Foo 85 | │   ├── FooConfig.cmake 86 | │   ├── FooConfigVersion.cmake 87 | │   ├── FooTargets.cmake 88 | │   ├── FooTargets-debug.cmake 89 | │   └── FooTargets-release.cmake 90 | ├── libfoo.a (Release) 91 | └── libfood.a (Debug) 92 | 93 | Uninstall library: 94 | 95 | > make uninstall 96 | 97 | 98 | #### Compilation scripts 99 | 100 | Please check the following files for more complex compilation examples: 101 | - [scripts/build_linux.sh](scripts/build_linux.sh) 102 | - [scripts/build_win.sh](scripts/build_win.sh) 103 | - [scripts/build_ninja.sh](scripts/build_ninja.sh) 104 | 105 | 106 | ### Static vs Shared 107 | 108 | By default, a static library will be generated. Modify `BUILD_SHARED_LIBS` in 109 | order to change this behavior. For example, 110 | 111 | > cd _build/ 112 | > cmake -DBUILD_SHARED_LIBS=ON .. 113 | 114 | 115 | 116 | ### How to use the library (internally in subfolders)? 117 | 118 | See the [example of internal subfolder](example_internal/). 119 | 120 | 121 | ### How to use the library (as dependency) in an external project? 122 | 123 | See the [example of external project](example_external/). 124 | Once the library is intalled, cmake would be able to find it using 125 | `find_package(...)` command. 126 | 127 | cmake_minimum_required(VERSION 3.9) 128 | project(Bar) 129 | 130 | find_package(Foo 1.2.3 REQUIRED) 131 | 132 | add_executable(bar bar.cpp) 133 | target_link_libraries(bar PRIVATE Foo::foo) 134 | 135 | Requirements will propagate automatically: 136 | * `Foo::foo` will link automatically, 137 | * headers can be included by C++ code like `#include `, 138 | * `FOO_DEBUG=1` added on Debug, 139 | * `FOO_DEBUG=0` added otherwise. 140 | 141 | 142 | ### How to use the library as submodule (using add_subdirectory)? 143 | 144 | If `Foo` library is intended to be use as a Git submodule: 145 | 146 | > git submodule add https://github.com//Foo Foo 147 | 148 | In the `CMakeLists.txt` where the `Foo` submodule will be used, 149 | add the command **add_subdirectory(...)**: 150 | 151 | [...] 152 | 153 | # Add 'Foo' library as submodule 154 | add_subdirectory(Foo) 155 | 156 | # Propagate usage requirements from Foo linked library 157 | target_link_libraries( PRIVATE Foo::foo) 158 | 159 | [...] 160 | 161 | 162 | ### How to create a library from this example? 163 | 164 | Follow these steps: 165 | 166 | * Copy files in a new folder, or clone with git: 167 | 168 | > git clone git@github.com:pablospe/cmake-example-library.git 169 | 170 | * Change project name in the top-level `CMakeLists.txt`. 171 | 172 | * Add `.cpp` and `.h` files in `foo/CMakeLists.txt`. 173 | 174 | * [Optional] Set variables: `LIBRARY_NAME` and `LIBRARY_FOLDER`. 175 | If it is not set explicitally, project name in lowercase will be used. 176 | See [cmake/SetEnv.cmake](cmake/SetEnv.cmake) file for implementation details. 177 | 178 | * [Optional] 'example_internal/' folder can be removed, it is the 'bar' 179 | example. In this case, remove the 'add_subdirectory(example_internal)' too. 180 | 181 | 182 | ### Documentation 183 | 184 | Some ideas from: 185 | * https://github.com/forexample/package-example 186 | 187 | Modern CMake tutorials (youtube): 188 | * C++Now 2017: Daniel Pfeifer 189 | [Effective CMake](https://www.youtube.com/watch?v=bsXLMQ6WgI) 190 | * CppCon 2018: Mateusz Pusz 191 | [Git, CMake, Conan - How to ship and reuse our C++ projects](https://www.youtube.com/watch?v=S4QSKLXdTtA) 192 | -------------------------------------------------------------------------------- /cmake/CMakeRegistry.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # CMake Registry 3 | # 4 | # Export package to CMake registry such that it can be easily found by 5 | # CMake even if it has not been installed to a standard directory. 6 | # 7 | # Note: this feature is disabled by default. Possible options: 8 | # -DCMAKE_REGISTRY_FOLDER="OFF" (disable CMake registry [default]) 9 | # -DCMAKE_REGISTRY_FOLDER="INSTALL_FOLDER" 10 | # -DCMAKE_REGISTRY_FOLDER="BUILD_FOLDER" 11 | # 12 | if( NOT (DEFINED CMAKE_REGISTRY_FOLDER) ) 13 | set(CMAKE_REGISTRY_FOLDER "OFF" 14 | CACHE STRING "Choose CMake registry folder." FORCE) 15 | endif() 16 | 17 | # Set possible values for cmake-gui 18 | set_property(CACHE CMAKE_REGISTRY_FOLDER PROPERTY STRINGS 19 | "BUILD_FOLDER" "INSTALL_FOLDER" "OFF") 20 | message(STATUS "CMAKE_REGISTRY_FOLDER: ${CMAKE_REGISTRY_FOLDER}") 21 | 22 | 23 | # CMake Register (build directory) 24 | if(CMAKE_REGISTRY_FOLDER STREQUAL "BUILD_FOLDER") 25 | export(PACKAGE ${PROJECT_NAME}) 26 | endif() 27 | 28 | # 29 | # Register installed package with CMake 30 | # 31 | # This function adds an entry to the CMake registry for packages with the 32 | # path of the directory where the package configuration file of the installed 33 | # package is located in order to help CMake find the package in a custom 34 | # installation prefix. This differs from CMake's export(PACKAGE) command 35 | # which registers the build directory instead. 36 | # 37 | function (register_package PACKAGE_FOLDER) 38 | if (NOT IS_ABSOLUTE "${PACKAGE_FOLDER}") 39 | set (PACKAGE_FOLDER "${CMAKE_INSTALL_PREFIX}/${PACKAGE_FOLDER}") 40 | endif () 41 | 42 | string (MD5 REGISTRY_ENTRY "${PACKAGE_FOLDER}") 43 | 44 | if (WIN32) 45 | install (CODE 46 | "execute_process ( 47 | COMMAND reg add \"HKCU\\\\Software\\\\Kitware\\\\CMake\\\\Packages\\\\${PROJECT_NAME}\" /v \"${REGISTRY_ENTRY}\" /d \"${PACKAGE_FOLDER}\" /t REG_SZ /f 48 | RESULT_VARIABLE RT 49 | ERROR_VARIABLE ERR 50 | OUTPUT_QUIET 51 | ) 52 | if (RT EQUAL 0) 53 | message (STATUS \"Register: Added HKEY_CURRENT_USER\\\\Software\\\\Kitware\\\\CMake\\\\Packages\\\\${PROJECT_NAME}\\\\${REGISTRY_ENTRY}\") 54 | else () 55 | string (STRIP \"\${ERR}\" ERR) 56 | message (STATUS \"Register: Failed to add registry entry: \${ERR}\") 57 | endif ()" 58 | ) 59 | elseif (IS_DIRECTORY "$ENV{HOME}") 60 | file (WRITE "${PROJECT_BINARY_DIR}/${PROJECT_NAME}-registry-entry" "${PACKAGE_FOLDER}") 61 | install ( 62 | FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}-registry-entry" 63 | DESTINATION "$ENV{HOME}/.cmake/packages/${PROJECT_NAME}" 64 | RENAME "${REGISTRY_ENTRY}" 65 | ) 66 | message (STATUS "CMake registry: $ENV{HOME}/.cmake/packages/${PROJECT_NAME}") 67 | endif () 68 | endfunction () 69 | 70 | # CMake Register (install directory) 71 | if(CMAKE_REGISTRY_FOLDER STREQUAL "INSTALL_FOLDER") 72 | register_package(${CONFIG_INSTALL_DIR}) 73 | endif () 74 | -------------------------------------------------------------------------------- /cmake/Config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | if(NOT TARGET ${PROJECT_NAME}::${LIBRARY_NAME}) 4 | include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") 5 | endif() 6 | 7 | set(@PROJECT_NAME_UPPERCASE@_LIBRARIES @PROJECT_NAME@::@LIBRARY_NAME@) 8 | 9 | check_required_components("@PROJECT_NAME@") 10 | -------------------------------------------------------------------------------- /cmake/LibraryConfig.cmake: -------------------------------------------------------------------------------- 1 | # Target 2 | add_library(${LIBRARY_NAME} 3 | ${SOURCES} 4 | ${HEADERS_PUBLIC} 5 | ${HEADERS_PRIVATE} 6 | ) 7 | 8 | # Alias: 9 | # - Foo::foo alias of foo 10 | add_library(${PROJECT_NAME}::${LIBRARY_NAME} ALIAS ${LIBRARY_NAME}) 11 | 12 | # C++11 13 | target_compile_features(${LIBRARY_NAME} PUBLIC cxx_std_11) 14 | 15 | # Add definitions for targets 16 | # Values: 17 | # - Debug : -DFOO_DEBUG=1 18 | # - Release: -DFOO_DEBUG=0 19 | # - others : -DFOO_DEBUG=0 20 | target_compile_definitions(${LIBRARY_NAME} PUBLIC 21 | "${PROJECT_NAME_UPPERCASE}_DEBUG=$") 22 | 23 | # Global includes. Used by all targets 24 | # Note: 25 | # - header can be included by C++ code `#include ` 26 | # - header location in project: ${CMAKE_CURRENT_BINARY_DIR}/generated_headers 27 | target_include_directories( 28 | ${LIBRARY_NAME} PUBLIC 29 | "$" 30 | "$" 31 | "$" 32 | ) 33 | 34 | # Targets: 35 | # - /lib/libfoo.a 36 | # - header location after install: /foo/foo.h 37 | # - headers can be included by C++ code `#include ` 38 | install( 39 | TARGETS "${LIBRARY_NAME}" 40 | EXPORT "${TARGETS_EXPORT_NAME}" 41 | LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" 42 | ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" 43 | RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" 44 | INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" 45 | ) 46 | 47 | # Headers: 48 | # - foo/*.h -> /include/foo/*.h 49 | install( 50 | FILES ${HEADERS_PUBLIC} 51 | DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${LIBRARY_FOLDER}" 52 | ) 53 | 54 | # Headers: 55 | # - generated_headers/foo/version.h -> /include/foo/version.h 56 | install( 57 | FILES "${GENERATED_HEADERS_DIR}/${LIBRARY_FOLDER}/version.h" 58 | DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${LIBRARY_FOLDER}" 59 | ) 60 | 61 | # Config 62 | # - /lib/cmake/Foo/FooConfig.cmake 63 | # - /lib/cmake/Foo/FooConfigVersion.cmake 64 | install( 65 | FILES "${PROJECT_CONFIG_FILE}" 66 | "${VERSION_CONFIG_FILE}" 67 | DESTINATION "${CONFIG_INSTALL_DIR}" 68 | ) 69 | 70 | # Config 71 | # - /lib/cmake/Foo/FooTargets.cmake 72 | install( 73 | EXPORT "${TARGETS_EXPORT_NAME}" 74 | FILE "${PROJECT_NAME}Targets.cmake" 75 | DESTINATION "${CONFIG_INSTALL_DIR}" 76 | NAMESPACE "${PROJECT_NAME}::" 77 | ) 78 | -------------------------------------------------------------------------------- /cmake/SetEnv.cmake: -------------------------------------------------------------------------------- 1 | # Set PROJECT_NAME_UPPERCASE and PROJECT_NAME_LOWERCASE variables 2 | string(TOUPPER ${PROJECT_NAME} PROJECT_NAME_UPPERCASE) 3 | string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWERCASE) 4 | 5 | # Library name (by default is the project name) 6 | if(NOT LIBRARY_NAME) 7 | set(LIBRARY_NAME ${PROJECT_NAME_LOWERCASE}) 8 | endif() 9 | 10 | # Library folder name (by default is the project name in lowercase) 11 | # Example: #include 12 | if(NOT LIBRARY_FOLDER) 13 | set(LIBRARY_FOLDER ${PROJECT_NAME_LOWERCASE}) 14 | endif() 15 | 16 | # Make sure different configurations don't collide 17 | set(CMAKE_DEBUG_POSTFIX "d") 18 | 19 | # Select library type (default: STATIC) 20 | option(BUILD_SHARED_LIBS "Build ${LIBRARY_NAME} as a shared library." OFF) 21 | message(STATUS "BUILD_SHARED_LIBS: ${BUILD_SHARED_LIBS}") 22 | 23 | # Build type (default: RELEASE) 24 | # 25 | # No reason to set CMAKE_CONFIGURATION_TYPES if it's not a multiconfig generator 26 | # Also no reason of using CMAKE_BUILD_TYPE if it's a multiconfig generator. 27 | # 28 | get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) 29 | if(isMultiConfig) 30 | set(CMAKE_CONFIGURATION_TYPES 31 | "Release;Debug;MinSizeRel;RelWithDebInfo" CACHE STRING "" FORCE) 32 | 33 | message(STATUS "CMAKE_CONFIGURATION_TYPES: ${CMAKE_CONFIGURATION_TYPES}") 34 | message(STATUS "CMAKE_GENERATOR: Multi-config") 35 | else() 36 | # Set a default build type if none was specified 37 | if(NOT CMAKE_BUILD_TYPE) 38 | set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) 39 | endif() 40 | 41 | # Set the possible values of build type for cmake-gui 42 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS 43 | "Release" "Debug" "MinSizeRel" "RelWithDebInfo") 44 | 45 | message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") 46 | message(STATUS "CMAKE_GENERATOR: Single-config") 47 | endif() 48 | message(STATUS "CMAKE_GENERATOR: ${CMAKE_GENERATOR}") 49 | 50 | # Generated headers folder 51 | set(GENERATED_HEADERS_DIR 52 | "${CMAKE_CURRENT_BINARY_DIR}/generated_headers" 53 | ) 54 | 55 | # Create 'version.h' 56 | configure_file( 57 | "${PROJECT_SOURCE_DIR}/${LIBRARY_FOLDER}/version.h.in" 58 | "${GENERATED_HEADERS_DIR}/${LIBRARY_FOLDER}/version.h" 59 | @ONLY 60 | ) 61 | 62 | # Introduce variables: 63 | # - CMAKE_INSTALL_LIBDIR 64 | # - CMAKE_INSTALL_BINDIR 65 | # - CMAKE_INSTALL_INCLUDEDIR 66 | include(GNUInstallDirs) 67 | 68 | # Layout. This works for all platforms: 69 | # - /lib*/cmake/ 70 | # - /lib*/ 71 | # - /include/ 72 | set(CONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") 73 | 74 | # Configuration 75 | set(GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") 76 | set(VERSION_CONFIG_FILE "${GENERATED_DIR}/${PROJECT_NAME}ConfigVersion.cmake") 77 | set(PROJECT_CONFIG_FILE "${GENERATED_DIR}/${PROJECT_NAME}Config.cmake") 78 | set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets") 79 | 80 | # Include module with functions: 81 | # - write_basic_package_version_file(...) 82 | # - configure_package_config_file(...) 83 | include(CMakePackageConfigHelpers) 84 | 85 | # Configure 'ConfigVersion.cmake' 86 | # Use: 87 | # - PROJECT_VERSION 88 | write_basic_package_version_file( 89 | "${VERSION_CONFIG_FILE}" 90 | VERSION "${${PROJECT_NAME}_VERSION}" 91 | COMPATIBILITY SameMajorVersion 92 | ) 93 | 94 | # Configure 'Config.cmake' 95 | # Use variables: 96 | # - TARGETS_EXPORT_NAME 97 | # - PROJECT_NAME 98 | configure_package_config_file( 99 | "${PROJECT_SOURCE_DIR}/cmake/Config.cmake.in" 100 | "${PROJECT_CONFIG_FILE}" 101 | INSTALL_DESTINATION "${CONFIG_INSTALL_DIR}" 102 | ) 103 | 104 | # Uninstall targets 105 | configure_file("${PROJECT_SOURCE_DIR}/cmake/Uninstall.cmake.in" 106 | "${GENERATED_DIR}/Uninstall.cmake" 107 | IMMEDIATE @ONLY) 108 | add_custom_target(uninstall 109 | COMMAND ${CMAKE_COMMAND} -P ${GENERATED_DIR}/Uninstall.cmake) 110 | 111 | # Always full RPATH (for shared libraries) 112 | # https://gitlab.kitware.com/cmake/community/-/wikis/doc/cmake/RPATH-handling 113 | if(BUILD_SHARED_LIBS) 114 | # use, i.e. don't skip the full RPATH for the build tree 115 | set(CMAKE_SKIP_BUILD_RPATH FALSE) 116 | 117 | # when building, don't use the install RPATH already 118 | # (but later on when installing) 119 | set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) 120 | 121 | set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") 122 | 123 | # add the automatically determined parts of the RPATH 124 | # which point to directories outside the build tree to the install RPATH 125 | set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) 126 | 127 | # the RPATH to be used when installing, but only if it's not a system directory 128 | list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir) 129 | if("${isSystemDir}" STREQUAL "-1") 130 | set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") 131 | endif() 132 | endif() 133 | 134 | # CMake Registry 135 | include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/CMakeRegistry.cmake) 136 | -------------------------------------------------------------------------------- /cmake/Uninstall.cmake.in: -------------------------------------------------------------------------------- 1 | # 2 | # Based on: 3 | # http://www.cmake.org/Wiki/CMake_FAQ#Can_I_do_.22make_uninstall.22_with_CMake.3F 4 | # 5 | 6 | # 'delete_empty_folder' function 7 | function(delete_empty_folder DIR) 8 | if(NOT EXISTS ${DIR}) 9 | return() 10 | endif() 11 | 12 | # check if folder is empty 13 | file(GLOB RESULT "${DIR}/*") 14 | list(LENGTH RESULT RES_LEN) 15 | if(RES_LEN EQUAL 0) 16 | message(STATUS "Delete empty folder ${DIR}") 17 | file(REMOVE_RECURSE ${DIR}) 18 | else() 19 | # message(STATUS "${DIR} is not empty! It won't be removed.") 20 | # message(STATUS "FILES = ${RESULT}") 21 | endif() 22 | endfunction(delete_empty_folder) 23 | 24 | # find 'install_manifest.txt' 25 | if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 26 | message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 27 | endif() 28 | 29 | # remove files from 'install_manifest.txt' 30 | message(STATUS "") 31 | message(STATUS "Removing files from 'install_manifest.txt'") 32 | file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) 33 | string(REGEX REPLACE "\n" ";" files "${files}") 34 | foreach(file ${files}) 35 | message(STATUS "Uninstalling $ENV{DESTDIR}${file}") 36 | if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 37 | exec_program("@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" 38 | OUTPUT_VARIABLE rm_out 39 | RETURN_VALUE rm_retval) 40 | if(NOT "${rm_retval}" STREQUAL 0) 41 | message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") 42 | endif() 43 | else() 44 | message(STATUS "File $ENV{DESTDIR}${file} does not exist.") 45 | endif() 46 | 47 | # create list of folders 48 | get_filename_component(FOLDER ${file} DIRECTORY) 49 | set(FOLDERS ${FOLDERS} ${FOLDER}) 50 | endforeach(file) 51 | 52 | 53 | # remove empty folders 54 | message(STATUS "") 55 | message(STATUS "Removing empty folders") 56 | 57 | list(REMOVE_DUPLICATES FOLDERS) 58 | foreach(dir ${FOLDERS}) 59 | # message(STATUS ${dir}) 60 | delete_empty_folder(${dir}) 61 | # message(STATUS "") 62 | endforeach(dir) 63 | 64 | delete_empty_folder("@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_INCLUDEDIR@") 65 | delete_empty_folder("@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_BINDIR@") 66 | delete_empty_folder("@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@/cmake") 67 | delete_empty_folder("@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@") 68 | message(STATUS "") 69 | -------------------------------------------------------------------------------- /example_external/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.9) 2 | project(Bar) 3 | 4 | # find package Foo (example library) 5 | find_package(Foo 1.2.3 CONFIG REQUIRED) 6 | 7 | # add binary 8 | add_executable(bar bar.cpp) 9 | 10 | # add library 11 | target_link_libraries(bar PRIVATE Foo::foo) 12 | -------------------------------------------------------------------------------- /example_external/bar.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) { 4 | foo_print_version(); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /example_internal/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(bar bar.cpp) 2 | 3 | target_link_libraries(bar PRIVATE Foo::foo) 4 | 5 | install( 6 | TARGETS bar 7 | RUNTIME DESTINATION bin 8 | ) 9 | -------------------------------------------------------------------------------- /example_internal/bar.cpp: -------------------------------------------------------------------------------- 1 | #include "foo/foo.h" 2 | 3 | int main(int argc, char *argv[]) { 4 | foo_print_version(); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /foo/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Set SOURCES variable 2 | set(SOURCES 3 | foo.cpp 4 | ) 5 | 6 | # Set HEADERS_PUBLIC variable (public headers, included in the library) 7 | set(HEADERS_PUBLIC 8 | foo.h 9 | ) 10 | 11 | # Set HEADERS_PRIVATE variable, if needed. 12 | # (these private headers won't be included in the library) 13 | # set(HEADERS_PRIVATE 14 | # foo_private.h 15 | # ) 16 | 17 | include(${PROJECT_SOURCE_DIR}/cmake/LibraryConfig.cmake) 18 | -------------------------------------------------------------------------------- /foo/foo.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | void foo_print_version(void) 6 | { 7 | #if (FOO_DEBUG) 8 | const char *m = "Debug"; 9 | #else 10 | const char *m = "Not debug"; 11 | #endif 12 | 13 | printf("This is foo version %s (%s)\n", FOO_VERSION, m); 14 | } 15 | -------------------------------------------------------------------------------- /foo/foo.h: -------------------------------------------------------------------------------- 1 | #ifndef FOO_FOO_H 2 | #define FOO_FOO_H 3 | 4 | #include 5 | 6 | void foo_print_version(void); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /foo/version.h.in: -------------------------------------------------------------------------------- 1 | #ifndef @PROJECT_NAME_UPPERCASE@_VERSION_ 2 | #define @PROJECT_NAME_UPPERCASE@_VERSION_ 3 | 4 | #define @PROJECT_NAME_UPPERCASE@_MAJOR_VERSION (@PROJECT_VERSION_MAJOR@) 5 | #define @PROJECT_NAME_UPPERCASE@_MINOR_VERSION (@PROJECT_VERSION_MINOR@) 6 | #define @PROJECT_NAME_UPPERCASE@_PATCH_VERSION (@PROJECT_VERSION_PATCH@) 7 | #define @PROJECT_NAME_UPPERCASE@_VERSION "@PROJECT_VERSION@" 8 | 9 | #endif // @PROJECT_NAME_UPPERCASE@_VERSION_ 10 | -------------------------------------------------------------------------------- /scripts/build_example_external.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script can be called from anywhere and allows to build out of source. 4 | 5 | # Determine script absolute path 6 | SCRIPT_ABS_PATH=$(readlink -f ${BASH_SOURCE[0]}) 7 | SCRIPT_ABS_PATH=$(dirname ${SCRIPT_ABS_PATH}) 8 | 9 | # switch to root folder, where top-level CMakeLists.txt lives 10 | ROOT=$(readlink -f ${SCRIPT_ABS_PATH}/../) 11 | cd $ROOT 12 | 13 | # Choose build type 14 | BUILD_TYPE=Release 15 | # BUILD_TYPE=Debug 16 | 17 | # Choose build type 18 | BUILD_DIR=_build 19 | 20 | # Choose install folder 21 | INSTALL_DIR=_install 22 | 23 | # Options summary 24 | echo "" 25 | echo "BUILD_TYPE =" ${BUILD_TYPE} 26 | echo "BUILD_DIR =" ${ROOT}/example_external/${BUILD_DIR}/ 27 | echo "INSTALL_DIR =" ${ROOT}/example_external/${INSTALL_DIR}/ 28 | echo "" 29 | 30 | 31 | # ------------------------------ 32 | # example_external (for testing) 33 | # ------------------------------ 34 | printf "\n\n ----- example_external ----- \n\n" 35 | 36 | # clean 37 | # rm -fr example_external/${BUILD_DIR} 38 | 39 | SO=`uname` 40 | if [[ $SO == "Linux" ]]; then 41 | echo "Running on Linux" 42 | 43 | # cmake 44 | cmake \ 45 | -S ${ROOT}/example_external/ \ 46 | -B ${ROOT}/example_external/${BUILD_DIR} \ 47 | -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ 48 | -DFoo_DIR="${ROOT}/${INSTALL_DIR}/lib/cmake/Foo/" 49 | 50 | # compile 51 | cmake \ 52 | --build ${ROOT}/example_external/${BUILD_DIR} \ 53 | -j 8 54 | 55 | else 56 | echo "Running on Windows" 57 | 58 | # cmake 59 | cmake \ 60 | -S ${ROOT}/example_external/ \ 61 | -B ${ROOT}/example_external/${BUILD_DIR} \ 62 | -DFoo_DIR="${ROOT}/${INSTALL_DIR}/lib/cmake/Foo/" 63 | 64 | # compile 65 | cmake \ 66 | --build ${ROOT}/example_external/${BUILD_DIR} \ 67 | --config ${BUILD_TYPE} \ 68 | -j 8 69 | fi 70 | 71 | 72 | # run 73 | BIN_PATH=${ROOT}/example_external/${BUILD_DIR} 74 | echo ${BIN_PATH}/${BUILD_TYPE}/ 75 | if [ -d "${BIN_PATH}/${BUILD_TYPE}" ]; then # multi-config generator 76 | BIN_PATH=${BIN_PATH}/${BUILD_TYPE} 77 | fi 78 | ${BIN_PATH}/bar 79 | -------------------------------------------------------------------------------- /scripts/build_linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script can be called from anywhere and allows to build out of source. 4 | 5 | # Determine script absolute path 6 | SCRIPT_ABS_PATH=$(readlink -f ${BASH_SOURCE[0]}) 7 | SCRIPT_ABS_PATH=$(dirname ${SCRIPT_ABS_PATH}) 8 | 9 | # switch to root folder, where top-level CMakeLists.txt lives 10 | ROOT=$(readlink -f ${SCRIPT_ABS_PATH}/../) 11 | cd $ROOT 12 | 13 | # Build type 14 | BUILD_TYPE=Release 15 | # BUILD_TYPE=Debug 16 | 17 | # Build folder 18 | BUILD_DIR=_build 19 | 20 | # Installation folder 21 | INSTALL_DIR=_install 22 | 23 | # Library type 24 | BUILD_SHARED_LIBS=OFF # Static 25 | # BUILD_SHARED_LIBS=ON # Shared 26 | 27 | # Options summary 28 | echo "" 29 | echo "BUILD_TYPE =" ${BUILD_TYPE} 30 | echo "BUILD_DIR =" ${ROOT}/${BUILD_DIR}/ 31 | echo "INSTALL_DIR =" ${ROOT}/${INSTALL_DIR}/ 32 | echo "BUILD_SHARED_LIBS =" ${BUILD_SHARED_LIBS} 33 | echo "" 34 | 35 | 36 | # clean 37 | # rm -fr ${BUILD_DIR} ${INSTALL_DIR} 38 | 39 | # cmake 40 | cmake \ 41 | -S . \ 42 | -B ${BUILD_DIR} \ 43 | -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ 44 | -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} \ 45 | -DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" 46 | 47 | # compile & install 48 | cmake \ 49 | --build ${BUILD_DIR} \ 50 | --target install \ 51 | -j 8 52 | -------------------------------------------------------------------------------- /scripts/build_ninja.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script can be called from anywhere and allows to build out of source. 4 | 5 | # Determine script absolute path 6 | SCRIPT_ABS_PATH=$(readlink -f ${BASH_SOURCE[0]}) 7 | SCRIPT_ABS_PATH=$(dirname ${SCRIPT_ABS_PATH}) 8 | 9 | # switch to root folder, where top-level CMakeLists.txt lives 10 | ROOT=$(readlink -f ${SCRIPT_ABS_PATH}/../) 11 | cd $ROOT 12 | 13 | # Build type 14 | BUILD_TYPE=Release 15 | # BUILD_TYPE=Debug 16 | 17 | # Build folder 18 | BUILD_DIR=_build 19 | 20 | # Installation folder 21 | INSTALL_DIR=_install 22 | 23 | # Library type 24 | BUILD_SHARED_LIBS=OFF # Static 25 | # BUILD_SHARED_LIBS=ON # Shared 26 | 27 | # Options summary 28 | echo "" 29 | echo "BUILD_TYPE =" ${BUILD_TYPE} 30 | echo "BUILD_DIR =" ${ROOT}/${BUILD_DIR}/ 31 | echo "INSTALL_DIR =" ${ROOT}/${INSTALL_DIR}/ 32 | echo "BUILD_SHARED_LIBS =" ${BUILD_SHARED_LIBS} 33 | echo "" 34 | 35 | 36 | # clean 37 | # rm -fr ${BUILD_DIR} ${INSTALL_DIR} 38 | 39 | # cmake 40 | cmake \ 41 | -S . \ 42 | -B ${BUILD_DIR} \ 43 | -G"Ninja" \ 44 | -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ 45 | -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} \ 46 | -DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" 47 | 48 | # For multi-config generator: 49 | # -G"Ninja Multi-Config" \ 50 | # -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ (and remove this line) 51 | 52 | # compile & install 53 | cmake \ 54 | --build ${BUILD_DIR} \ 55 | --target install \ 56 | -j 8 57 | -------------------------------------------------------------------------------- /scripts/build_win.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script can be called from anywhere and allows to build out of source. 4 | # Note: it is assumed Git for Windows is installed (https://gitforwindows.org/). 5 | 6 | # Determine script absolute path 7 | SCRIPT_ABS_PATH=$(readlink -f ${BASH_SOURCE[0]}) 8 | SCRIPT_ABS_PATH=$(dirname ${SCRIPT_ABS_PATH}) 9 | 10 | # switch to root folder, where top-level CMakeLists.txt lives 11 | ROOT=$(readlink -f ${SCRIPT_ABS_PATH}/../) 12 | cd $ROOT 13 | 14 | # Build type 15 | BUILD_TYPE=Release 16 | # BUILD_TYPE=Debug 17 | 18 | # Build folder 19 | BUILD_DIR=_build 20 | 21 | # Installation folder 22 | INSTALL_DIR=_install 23 | 24 | # Library type 25 | BUILD_SHARED_LIBS=OFF # Static 26 | # BUILD_SHARED_LIBS=ON # Shared 27 | 28 | # Options summary 29 | echo "" 30 | echo "BUILD_TYPE =" ${BUILD_TYPE} 31 | echo "BUILD_DIR =" ${ROOT}/${BUILD_DIR}/ 32 | echo "INSTALL_DIR =" ${ROOT}/${INSTALL_DIR}/ 33 | echo "BUILD_SHARED_LIBS =" ${BUILD_SHARED_LIBS} 34 | echo "" 35 | 36 | 37 | # clean 38 | # rm -fr ${BUILD_DIR} ${INSTALL_DIR} 39 | 40 | # cmake 41 | cmake \ 42 | -S . \ 43 | -B ${BUILD_DIR} \ 44 | -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} \ 45 | -DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" 46 | 47 | # compile & install 48 | cmake \ 49 | --build ${BUILD_DIR} \ 50 | --config ${BUILD_TYPE} \ 51 | --target install \ 52 | -j 8 53 | --------------------------------------------------------------------------------